source: Dev/trunk/rdfapi/util/adodb/drivers/adodb-oci8.inc.php @ 12

Last change on this file since 12 was 12, checked in by basvannuland, 14 years ago

Added RAP RDF API
Added RDF reader writer for save and load survey

File size: 43.7 KB
Line 
1<?php
2/*
3
4  version V4.94 23 Jan 2007 (c) 2000-2007 John Lim. All rights reserved.
5
6  Released under both BSD license and Lesser GPL library license.
7  Whenever there is any discrepancy between the two licenses,
8  the BSD license will take precedence.
9
10  Latest version is available at http://adodb.sourceforge.net
11 
12  Code contributed by George Fourlanos <fou@infomap.gr>
13 
14  13 Nov 2000 jlim - removed all ora_* references.
15*/
16
17// security - hide paths
18if (!defined('ADODB_DIR')) die();
19
20/*
21NLS_Date_Format
22Allows you to use a date format other than the Oracle Lite default. When a literal
23character string appears where a date value is expected, the Oracle Lite database
24tests the string to see if it matches the formats of Oracle, SQL-92, or the value
25specified for this parameter in the POLITE.INI file. Setting this parameter also
26defines the default format used in the TO_CHAR or TO_DATE functions when no
27other format string is supplied.
28
29For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
30yy-mm-dd or yyyy-mm-dd.
31
32Using 'RR' in the format forces two-digit years less than or equal to 49 to be
33interpreted as years in the 21st century (2000–2049), and years over 50 as years in
34the 20th century (1950–1999). Setting the RR format as the default for all two-digit
35year entries allows you to become year-2000 compliant. For example:
36NLS_DATE_FORMAT='RR-MM-DD'
37
38You can also modify the date format using the ALTER SESSION command.
39*/
40
41# define the LOB descriptor type for the given type
42# returns false if no LOB descriptor
43function oci_lob_desc($type) {
44        switch ($type) {
45                case OCI_B_BFILE: $result = OCI_D_FILE; break;
46                case OCI_B_CFILEE: $result = OCI_D_FILE; break;
47                case OCI_B_CLOB: $result = OCI_D_LOB; break;
48                case OCI_B_BLOB: $result = OCI_D_LOB; break;
49                case OCI_B_ROWID: $result = OCI_D_ROWID; break;
50                default: $result = false; break;
51        }
52        return $result;
53}
54
55class ADODB_oci8 extends ADOConnection {
56        var $databaseType = 'oci8';
57        var $dataProvider = 'oci8';
58        var $replaceQuote = "''"; // string to use to replace quotes
59        var $concat_operator='||';
60        var $sysDate = "TRUNC(SYSDATE)";
61        var $sysTimeStamp = 'SYSDATE';
62        var $metaDatabasesSQL = "SELECT USERNAME FROM ALL_USERS WHERE USERNAME NOT IN ('SYS','SYSTEM','DBSNMP','OUTLN') ORDER BY 1";
63        var $_stmt;
64        var $_commit = OCI_COMMIT_ON_SUCCESS;
65        var $_initdate = true; // init date to YYYY-MM-DD
66        var $metaTablesSQL = "select table_name,table_type from cat where table_type in ('TABLE','VIEW') and table_name not like 'BIN\$%'"; // bin$ tables are recycle bin tables
67        var $metaColumnsSQL = "select cname,coltype,width, SCALE, PRECISION, NULLS, DEFAULTVAL from col where tname='%s' order by colno"; //changed by smondino@users.sourceforge. net
68        var $_bindInputArray = true;
69        var $hasGenID = true;
70        var $_genIDSQL = "SELECT (%s.nextval) FROM DUAL";
71        var $_genSeqSQL = "CREATE SEQUENCE %s START WITH %s";
72        var $_dropSeqSQL = "DROP SEQUENCE %s";
73        var $hasAffectedRows = true;
74        var $random = "abs(mod(DBMS_RANDOM.RANDOM,10000001)/10000000)";
75        var $noNullStrings = false;
76        var $connectSID = false;
77        var $_bind = false;
78        var $_nestedSQL = true;
79        var $_hasOCIFetchStatement = false;
80        var $_getarray = false; // currently not working
81        var $leftOuter = '';  // oracle wierdness, $col = $value (+) for LEFT OUTER, $col (+)= $value for RIGHT OUTER
82        var $session_sharing_force_blob = false; // alter session on updateblob if set to true
83        var $firstrows = true; // enable first rows optimization on SelectLimit()
84        var $selectOffsetAlg1 = 100; // when to use 1st algorithm of selectlimit.
85        var $NLS_DATE_FORMAT = 'YYYY-MM-DD';  // To include time, use 'RRRR-MM-DD HH24:MI:SS'
86        var $useDBDateFormatForTextInput=false;
87        var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
88        var $_refLOBs = array();
89       
90        // var $ansiOuter = true; // if oracle9
91   
92        function ADODB_oci8()
93        {
94                $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
95                if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_';
96        }
97       
98        /*  Function &MetaColumns($table) added by smondino@users.sourceforge.net*/
99        function &MetaColumns($table)
100        {
101        global $ADODB_FETCH_MODE;
102       
103                $false = false;
104                $save = $ADODB_FETCH_MODE;
105                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
106                if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
107               
108                $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
109               
110                if (isset($savem)) $this->SetFetchMode($savem);
111                $ADODB_FETCH_MODE = $save;
112                if (!$rs) {
113                        return $false;
114                }
115                $retarr = array();
116                while (!$rs->EOF) { //print_r($rs->fields);
117                        $fld = new ADOFieldObject();
118                        $fld->name = $rs->fields[0];
119                        $fld->type = $rs->fields[1];
120                        $fld->max_length = $rs->fields[2];
121                        $fld->scale = $rs->fields[3];
122                        if ($rs->fields[1] == 'NUMBER') {
123                                if ($rs->fields[3] == 0) $fld->type = 'INT';
124                        $fld->max_length = $rs->fields[4];
125                }       
126                        $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
127                        $fld->binary = (strpos($fld->type,'BLOB') !== false);
128                        $fld->default_value = $rs->fields[6];
129                       
130                        if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;     
131                        else $retarr[strtoupper($fld->name)] = $fld;
132                        $rs->MoveNext();
133                }
134                $rs->Close();
135                if (empty($retarr))
136                        return  $false;
137                else
138                        return $retarr;
139        }
140       
141        function Time()
142        {
143                $rs =& $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual");
144                if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
145               
146                return false;
147        }
148 
149/*
150
151  Multiple modes of connection are supported:
152 
153  a. Local Database
154    $conn->Connect(false,'scott','tiger');
155 
156  b. From tnsnames.ora
157    $conn->Connect(false,'scott','tiger',$tnsname);
158    $conn->Connect($tnsname,'scott','tiger');
159 
160  c. Server + service name
161    $conn->Connect($serveraddress,'scott,'tiger',$service_name);
162 
163  d. Server + SID
164        $conn->connectSID = true;
165        $conn->Connect($serveraddress,'scott,'tiger',$SID);
166
167
168Example TNSName:
169---------------
170NATSOFT.DOMAIN =
171  (DESCRIPTION =
172        (ADDRESS_LIST =
173          (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
174        )
175        (CONNECT_DATA =
176          (SERVICE_NAME = natsoft.domain)
177        )
178  )
179 
180  There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
181       
182*/
183        function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
184        {
185                if (!function_exists('OCIPLogon')) return null;
186               
187               
188        $this->_errorMsg = false;
189                $this->_errorCode = false;
190               
191                if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
192                        if (empty($argDatabasename)) $argDatabasename = $argHostname;
193                        else {
194                                if(strpos($argHostname,":")) {
195                                        $argHostinfo=explode(":",$argHostname);
196                                        $argHostname=$argHostinfo[0];
197                                        $argHostport=$argHostinfo[1];
198                                } else {
199                                        $argHostport = empty($this->port)?  "1521" : $this->port;
200                                }
201                               
202                                if ($this->connectSID) {
203                                        $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
204                                        .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
205                                } else
206                                        $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
207                                        .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
208                        }
209                }
210                               
211                //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
212                if ($mode==1) {
213                        $this->_connectionID = ($this->charSet) ?
214                                OCIPLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
215                                :
216                                OCIPLogon($argUsername,$argPassword, $argDatabasename)
217                                ;
218                        if ($this->_connectionID && $this->autoRollback)  OCIrollback($this->_connectionID);
219                } else if ($mode==2) {
220                        $this->_connectionID = ($this->charSet) ?
221                                OCINLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
222                                :
223                                OCINLogon($argUsername,$argPassword, $argDatabasename);
224                               
225                } else {
226                        $this->_connectionID = ($this->charSet) ?
227                                OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
228                                :
229                                OCILogon($argUsername,$argPassword, $argDatabasename);
230                }
231                if (!$this->_connectionID) return false;
232                if ($this->_initdate) {
233                        $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
234                }
235               
236                // looks like:
237                // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
238                // $vers = OCIServerVersion($this->_connectionID);
239                // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
240                return true;
241        }
242       
243        function ServerInfo()
244        {
245                $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
246                $arr['description'] = @OCIServerVersion($this->_connectionID);
247                $arr['version'] = ADOConnection::_findvers($arr['description']);
248                return $arr;
249        }
250                // returns true or false
251        function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
252        {
253                return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
254        }
255       
256        // returns true or false
257        function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
258        {
259                return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
260        }
261       
262        function _affectedrows()
263        {
264                if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt);
265                return 0;
266        }
267       
268        function IfNull( $field, $ifNull )
269        {
270                return " NVL($field, $ifNull) "; // if Oracle
271        }
272       
273        // format and return date string in database date format
274        function DBDate($d)
275        {
276                if (empty($d) && $d !== 0) return 'null';
277               
278                if (is_string($d)) $d = ADORecordSet::UnixDate($d);
279                return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->NLS_DATE_FORMAT."')";
280        }
281
282        function BindDate($d)
283        {
284                $d = ADOConnection::DBDate($d);
285                if (strncmp($d,"'",1)) return $d;
286               
287                return substr($d,1,strlen($d)-2);
288        }
289       
290        function BindTimeStamp($d)
291        {
292                $d = ADOConnection::DBTimeStamp($d);
293                if (strncmp($d,"'",1)) return $d;
294               
295                return substr($d,1,strlen($d)-2);
296        }
297       
298        // format and return date string in database timestamp format
299        function DBTimeStamp($ts)
300        {
301                if (empty($ts) && $ts !== 0) return 'null';
302                if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
303                return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')";
304        }
305       
306        function RowLock($tables,$where,$flds='1 as ignore')
307        {
308                if ($this->autoCommit) $this->BeginTrans();
309                return $this->GetOne("select $flds from $tables where $where for update");
310        }
311       
312        function &MetaTables($ttype=false,$showSchema=false,$mask=false)
313        {
314                if ($mask) {
315                        $save = $this->metaTablesSQL;
316                        $mask = $this->qstr(strtoupper($mask));
317                        $this->metaTablesSQL .= " AND upper(table_name) like $mask";
318                }
319                $ret =& ADOConnection::MetaTables($ttype,$showSchema);
320               
321                if ($mask) {
322                        $this->metaTablesSQL = $save;
323                }
324                return $ret;
325        }
326       
327        // Mark Newnham
328        function &MetaIndexes ($table, $primary = FALSE, $owner=false)
329        {
330        // save old fetch mode
331        global $ADODB_FETCH_MODE;
332
333        $save = $ADODB_FETCH_MODE;
334        $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
335
336        if ($this->fetchMode !== FALSE) {
337               $savem = $this->SetFetchMode(FALSE);
338        }
339
340                // get index details
341                $table = strtoupper($table);
342
343                // get Primary index
344                $primary_key = '';
345
346                $false = false;
347                $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table));
348                if ($row = $rs->FetchRow())
349                   $primary_key = $row[1]; //constraint_name
350
351                if ($primary==TRUE && $primary_key=='') {
352                         if (isset($savem))
353                $this->SetFetchMode($savem);
354                        $ADODB_FETCH_MODE = $save;
355                        return $false; //There is no primary key
356                }
357
358        $rs = $this->Execute(sprintf("SELECT ALL_INDEXES.INDEX_NAME, ALL_INDEXES.UNIQUENESS, ALL_IND_COLUMNS.COLUMN_POSITION, ALL_IND_COLUMNS.COLUMN_NAME FROM ALL_INDEXES,ALL_IND_COLUMNS WHERE UPPER(ALL_INDEXES.TABLE_NAME)='%s' AND ALL_IND_COLUMNS.INDEX_NAME=ALL_INDEXES.INDEX_NAME",$table));
359
360               
361        if (!is_object($rs)) {
362                        if (isset($savem))
363                                $this->SetFetchMode($savem);
364                        $ADODB_FETCH_MODE = $save;
365            return $false;
366        }
367
368                $indexes = array ();
369        // parse index data into array
370
371        while ($row = $rs->FetchRow()) {
372                        if ($primary && $row[0] != $primary_key) continue;
373            if (!isset($indexes[$row[0]])) {
374                                $indexes[$row[0]] = array(
375                                   'unique' => ($row[1] == 'UNIQUE'),
376                                   'columns' => array()
377                                );
378            }
379            $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3];
380        }
381
382        // sort columns by order in the index
383        foreach ( array_keys ($indexes) as $index ) {
384            ksort ($indexes[$index]['columns']);
385        }
386
387                if (isset($savem)) {
388            $this->SetFetchMode($savem);
389                        $ADODB_FETCH_MODE = $save;
390                }
391        return $indexes;
392        }
393       
394        function BeginTrans()
395        {       
396                if ($this->transOff) return true;
397                $this->transCnt += 1;
398                $this->autoCommit = false;
399                $this->_commit = OCI_DEFAULT;
400               
401                if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode);
402                return true;
403        }
404       
405        function CommitTrans($ok=true)
406        {
407                if ($this->transOff) return true;
408                if (!$ok) return $this->RollbackTrans();
409               
410                if ($this->transCnt) $this->transCnt -= 1;
411                $ret = OCIcommit($this->_connectionID);
412                $this->_commit = OCI_COMMIT_ON_SUCCESS;
413                $this->autoCommit = true;
414                return $ret;
415        }
416       
417        function RollbackTrans()
418        {
419                if ($this->transOff) return true;
420                if ($this->transCnt) $this->transCnt -= 1;
421                $ret = OCIrollback($this->_connectionID);
422                $this->_commit = OCI_COMMIT_ON_SUCCESS;
423                $this->autoCommit = true;
424                return $ret;
425        }
426       
427       
428        function SelectDB($dbName)
429        {
430                return false;
431        }
432
433        function ErrorMsg()
434        {
435                if ($this->_errorMsg !== false) return $this->_errorMsg;
436
437                if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
438                if (empty($arr)) {
439                        if (is_resource($this->_connectionID)) $arr = @OCIError($this->_connectionID);
440                        else $arr = @OCIError();
441                        if ($arr === false) return '';
442                }
443                $this->_errorMsg = $arr['message'];
444                $this->_errorCode = $arr['code'];
445                return $this->_errorMsg;
446        }
447
448        function ErrorNo()
449        {
450                if ($this->_errorCode !== false) return $this->_errorCode;
451               
452                if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
453                if (empty($arr)) {
454                        $arr = @OCIError($this->_connectionID);
455                        if ($arr == false) $arr = @OCIError();
456                        if ($arr == false) return '';
457                }
458               
459                $this->_errorMsg = $arr['message'];
460                $this->_errorCode = $arr['code'];
461               
462                return $arr['code'];
463        }
464       
465        // Format date column in sql string given an input format that understands Y M D
466        function SQLDate($fmt, $col=false)
467        {       
468                if (!$col) $col = $this->sysTimeStamp;
469                $s = 'TO_CHAR('.$col.",'";
470               
471                $len = strlen($fmt);
472                for ($i=0; $i < $len; $i++) {
473                        $ch = $fmt[$i];
474                        switch($ch) {
475                        case 'Y':
476                        case 'y':
477                                $s .= 'YYYY';
478                                break;
479                        case 'Q':
480                        case 'q':
481                                $s .= 'Q';
482                                break;
483                               
484                        case 'M':
485                                $s .= 'Mon';
486                                break;
487                               
488                        case 'm':
489                                $s .= 'MM';
490                                break;
491                        case 'D':
492                        case 'd':
493                                $s .= 'DD';
494                                break;
495                       
496                        case 'H':
497                                $s.= 'HH24';
498                                break;
499                               
500                        case 'h':
501                                $s .= 'HH';
502                                break;
503                               
504                        case 'i':
505                                $s .= 'MI';
506                                break;
507                       
508                        case 's':
509                                $s .= 'SS';
510                                break;
511                       
512                        case 'a':
513                        case 'A':
514                                $s .= 'AM';
515                                break;
516                               
517                        case 'w':
518                                $s .= 'D';
519                                break;
520                               
521                        case 'l':
522                                $s .= 'DAY';
523                                break;
524                               
525                         case 'W':
526                                $s .= 'WW';
527                                break;
528                               
529                        default:
530                        // handle escape characters...
531                                if ($ch == '\\') {
532                                        $i++;
533                                        $ch = substr($fmt,$i,1);
534                                }
535                                if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
536                                else $s .= '"'.$ch.'"';
537                               
538                        }
539                }
540                return $s. "')";
541        }
542       
543       
544        /*
545        This algorithm makes use of
546       
547        a. FIRST_ROWS hint
548        The FIRST_ROWS hint explicitly chooses the approach to optimize response time,
549        that is, minimum resource usage to return the first row. Results will be returned
550        as soon as they are identified.
551
552        b. Uses rownum tricks to obtain only the required rows from a given offset.
553         As this uses complicated sql statements, we only use this if the $offset >= 100.
554         This idea by Tomas V V Cox.
555         
556         This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
557         out this function then, and the slower SelectLimit() in the base class will be used.
558        */
559        function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
560        {
561                // seems that oracle only supports 1 hint comment in 8i
562                if ($this->firstrows) {
563                        if (strpos($sql,'/*+') !== false)
564                                $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
565                        else
566                                $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
567                }
568               
569                if ($offset < $this->selectOffsetAlg1) {
570                        if ($nrows > 0) {       
571                                if ($offset > 0) $nrows += $offset;
572                                //$inputarr['adodb_rownum'] = $nrows;
573                                if ($this->databaseType == 'oci8po') {
574                                        $sql = "select * from (".$sql.") where rownum <= ?";
575                                } else {
576                                        $sql = "select * from (".$sql.") where rownum <= :adodb_offset";
577                                }
578                                $inputarr['adodb_offset'] = $nrows;
579                                $nrows = -1;
580                        }
581                        // note that $nrows = 0 still has to work ==> no rows returned
582
583                        $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
584                        return $rs;
585                       
586                } else {
587                         // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
588                       
589                         // Let Oracle return the name of the columns
590                        $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL";
591                         
592                        $false = false;
593                        if (! $stmt_arr = $this->Prepare($q_fields)) {
594                                return $false;
595                        }
596                        $stmt = $stmt_arr[1];
597                         
598                         if (is_array($inputarr)) {
599                                foreach($inputarr as $k => $v) {
600                                        if (is_array($v)) {
601                                                if (sizeof($v) == 2) // suggested by g.giunta@libero.
602                                                        OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
603                                                else
604                                                        OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
605                                        } else {
606                                                $len = -1;
607                                                if ($v === ' ') $len = 1;
608                                                if (isset($bindarr)) {  // is prepared sql, so no need to ocibindbyname again
609                                                        $bindarr[$k] = $v;
610                                                } else {                                // dynamic sql, so rebind every time
611                                                        OCIBindByName($stmt,":$k",$inputarr[$k],$len);
612                                                }
613                                        }
614                                }
615                        }
616                       
617                         if (!OCIExecute($stmt, OCI_DEFAULT)) {
618                                 OCIFreeStatement($stmt);
619                                 return $false;
620                         }
621                         
622                         $ncols = OCINumCols($stmt);
623                         for ( $i = 1; $i <= $ncols; $i++ ) {
624                                 $cols[] = '"'.OCIColumnName($stmt, $i).'"';
625                         }
626                         $result = false;
627                       
628                         OCIFreeStatement($stmt);
629                         $fields = implode(',', $cols);
630                         $nrows += $offset;
631                         $offset += 1; // in Oracle rownum starts at 1
632                       
633                        if ($this->databaseType == 'oci8po') {
634                                         $sql = "SELECT $fields FROM".
635                                          "(SELECT rownum as adodb_rownum, $fields FROM".
636                                          " ($sql) WHERE rownum <= ?".
637                                          ") WHERE adodb_rownum >= ?";
638                                } else {
639                                         $sql = "SELECT $fields FROM".
640                                          "(SELECT rownum as adodb_rownum, $fields FROM".
641                                          " ($sql) WHERE rownum <= :adodb_nrows".
642                                          ") WHERE adodb_rownum >= :adodb_offset";
643                                }
644                                $inputarr['adodb_nrows'] = $nrows;
645                                $inputarr['adodb_offset'] = $offset;
646                               
647                        if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr);
648                        else $rs =& $this->Execute($sql,$inputarr);
649                        return $rs;
650                }
651       
652        }
653       
654        /**
655        * Usage:
656        * Store BLOBs and CLOBs
657        *
658        * Example: to store $var in a blob
659        *
660        *       $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
661        *       $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
662        *       
663        *       $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
664        *
665        *  to get length of LOB:
666        *       select DBMS_LOB.GETLENGTH(ablob) from TABLE
667        *
668        * If you are using CURSOR_SHARING = force, it appears this will case a segfault
669        * under oracle 8.1.7.0. Run:
670        *        $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
671        * before UpdateBlob() then...
672        */
673
674        function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
675        {
676               
677                //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
678               
679                switch(strtoupper($blobtype)) {
680                default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
681                case 'BLOB': $type = OCI_B_BLOB; break;
682                case 'CLOB': $type = OCI_B_CLOB; break;
683                }
684               
685                if ($this->databaseType == 'oci8po')
686                        $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
687                else
688                        $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
689               
690                $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
691                $arr['blob'] = array($desc,-1,$type);
692                if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
693                $commit = $this->autoCommit;
694                if ($commit) $this->BeginTrans();
695                $rs = $this->_Execute($sql,$arr);
696                if ($rez = !empty($rs)) $desc->save($val);
697                $desc->free();
698                if ($commit) $this->CommitTrans();
699                if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
700               
701                if ($rez) $rs->Close();
702                return $rez;
703        }
704       
705        /**
706        * Usage:  store file pointed to by $var in a blob
707        */
708        function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
709        {
710                switch(strtoupper($blobtype)) {
711                default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
712                case 'BLOB': $type = OCI_B_BLOB; break;
713                case 'CLOB': $type = OCI_B_CLOB; break;
714                }
715               
716                if ($this->databaseType == 'oci8po')
717                        $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
718                else
719                        $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
720               
721                $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
722                $arr['blob'] = array($desc,-1,$type);
723               
724                $this->BeginTrans();
725                $rs = ADODB_oci8::Execute($sql,$arr);
726                if ($rez = !empty($rs)) $desc->savefile($val);
727                $desc->free();
728                $this->CommitTrans();
729               
730                if ($rez) $rs->Close();
731                return $rez;
732        }
733
734                /**
735         * Execute SQL
736         *
737         * @param sql           SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
738         * @param [inputarr]    holds the input data to bind to. Null elements will be set to null.
739         * @return              RecordSet or false
740         */
741        function &Execute($sql,$inputarr=false)
742        {
743                if ($this->fnExecute) {
744                        $fn = $this->fnExecute;
745                        $ret =& $fn($this,$sql,$inputarr);
746                        if (isset($ret)) return $ret;
747                }
748                if ($inputarr) {
749                        #if (!is_array($inputarr)) $inputarr = array($inputarr);
750                       
751                        $element0 = reset($inputarr);
752                       
753                        # is_object check because oci8 descriptors can be passed in
754                        if (is_array($element0) && !is_object(reset($element0))) {
755                                if (is_string($sql))
756                                        $stmt = $this->Prepare($sql);
757                                else
758                                        $stmt = $sql;
759                                       
760                                foreach($inputarr as $arr) {
761                                        $ret =& $this->_Execute($stmt,$arr);
762                                        if (!$ret) return $ret;
763                                }
764                        } else {
765                                $ret =& $this->_Execute($sql,$inputarr);
766                        }
767                       
768                } else {
769                        $ret =& $this->_Execute($sql,false);
770                }
771
772                return $ret;
773        }
774       
775        /*
776                Example of usage:
777               
778                $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
779        */
780        function Prepare($sql,$cursor=false)
781        {
782        static $BINDNUM = 0;
783       
784                $stmt = OCIParse($this->_connectionID,$sql);
785
786                if (!$stmt) {
787                        $this->_errorMsg = false;
788                        $this->_errorCode = false;
789                        $arr = @OCIError($this->_connectionID);
790                        if ($arr === false) return false;
791               
792                        $this->_errorMsg = $arr['message'];
793                        $this->_errorCode = $arr['code'];
794                        return false;
795                }
796               
797                $BINDNUM += 1;
798               
799                $sttype = @OCIStatementType($stmt);
800                if ($sttype == 'BEGIN' || $sttype == 'DECLARE') {
801                        return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
802                }
803                return array($sql,$stmt,0,$BINDNUM);
804        }
805       
806        /*
807                Call an oracle stored procedure and returns a cursor variable as a recordset.
808                Concept by Robert Tuttle robert@ud.com
809               
810                Example:
811                        Note: we return a cursor variable in :RS2
812                        $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
813                       
814                        $rs = $db->ExecuteCursor(
815                                "BEGIN :RS2 = adodb.getdata(:VAR1); END;",
816                                'RS2',
817                                array('VAR1' => 'Mr Bean'));
818                       
819        */
820        function &ExecuteCursor($sql,$cursorName='rs',$params=false)
821        {
822                if (is_array($sql)) $stmt = $sql;
823                else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
824       
825                if (is_array($stmt) && sizeof($stmt) >= 5) {
826                        $hasref = true;
827                        $ignoreCur = false;
828                        $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
829                        if ($params) {
830                                foreach($params as $k => $v) {
831                                        $this->Parameter($stmt,$params[$k], $k);
832                                }
833                        }
834                } else
835                        $hasref = false;
836                       
837                $rs =& $this->Execute($stmt);
838                if ($rs) {
839                        if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]);
840                        else if ($hasref) $rs->_refcursor = $stmt[4];
841                }
842                return $rs;
843        }
844       
845        /*
846                Bind a variable -- very, very fast for executing repeated statements in oracle.
847                Better than using
848                        for ($i = 0; $i < $max; $i++) {
849                                $p1 = ?; $p2 = ?; $p3 = ?;
850                                $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)",
851                                        array($p1,$p2,$p3));
852                        }
853               
854                Usage:
855                        $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
856                        $DB->Bind($stmt, $p1);
857                        $DB->Bind($stmt, $p2);
858                        $DB->Bind($stmt, $p3);
859                        for ($i = 0; $i < $max; $i++) {
860                                $p1 = ?; $p2 = ?; $p3 = ?;
861                                $DB->Execute($stmt);
862                        }
863                       
864                Some timings:           
865                        ** Test table has 3 cols, and 1 index. Test to insert 1000 records
866                        Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
867                        Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
868                        Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
869                       
870                Now if PHP only had batch/bulk updating like Java or PL/SQL...
871       
872                Note that the order of parameters differs from OCIBindByName,
873                because we default the names to :0, :1, :2
874        */
875        function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false)
876        {
877               
878                if (!is_array($stmt)) return false;
879       
880        if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) {
881            return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
882        }
883       
884                if ($name == false) {
885                        if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type);
886                        else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
887                        $stmt[2] += 1;
888                } else if (oci_lob_desc($type)) {
889                        if ($this->debug) {
890                                ADOConnection::outp("<b>Bind</b>: name = $name");
891                        }
892            //we have to create a new Descriptor here
893                        $numlob = count($this->_refLOBs);
894                $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type));
895                        $this->_refLOBs[$numlob]['TYPE'] = $isOutput;
896                       
897                        $tmp = &$this->_refLOBs[$numlob]['LOB'];
898                $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type);
899                        if ($this->debug) {
900                                ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded");
901                        }
902                       
903                        // if type is input then write data to lob now
904                        if ($isOutput == false) {
905                                $var = $this->BlobEncode($var);
906                                $tmp->WriteTemporary($var);
907                                $this->_refLOBs[$numlob]['VAR'] = &$var;
908                                if ($this->debug) {
909                                        ADOConnection::outp("<b>Bind</b>: LOB has been written to temp");
910                                }
911                        } else {
912                                $this->_refLOBs[$numlob]['VAR'] = &$var;
913                        }
914                        $rez = $tmp;
915                } else {
916                        if ($this->debug)
917                                ADOConnection::outp("<b>Bind</b>: name = $name");
918                       
919                        if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
920                        else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
921                }
922               
923                return $rez;
924        }
925       
926        function Param($name,$type=false)
927        {
928                return ':'.$name;
929        }
930       
931        /*
932        Usage:
933                $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
934                $db->Parameter($stmt,$id,'myid');
935                $db->Parameter($stmt,$group,'group');
936                $db->Execute($stmt);
937               
938                @param $stmt Statement returned by Prepare() or PrepareSP().
939                @param $var PHP variable to bind to
940                @param $name Name of stored procedure variable name to bind to.
941                @param [$isOutput] Indicates direction of parameter 0/false=IN  1=OUT  2= IN/OUT. This is ignored in oci8.
942                @param [$maxLen] Holds an maximum length of the variable.
943                @param [$type] The data type of $var. Legal values depend on driver.
944               
945                See OCIBindByName documentation at php.net.
946        */
947        function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
948        {
949                        if  ($this->debug) {
950                                $prefix = ($isOutput) ? 'Out' : 'In';
951                                $ztype = (empty($type)) ? 'false' : $type;
952                                ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
953                        }
954                        return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput);
955        }
956       
957        /*
958        returns query ID if successful, otherwise false
959        this version supports:
960       
961           1. $db->execute('select * from table');
962           
963           2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
964                  $db->execute($prepared_statement, array(1,2,3));
965                 
966           3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
967           
968           4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
969                  $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3);
970                  $db->execute($stmt);
971        */
972        function _query($sql,$inputarr)
973        {
974                if (is_array($sql)) { // is prepared sql
975                        $stmt = $sql[1];
976                       
977                        // we try to bind to permanent array, so that OCIBindByName is persistent
978                        // and carried out once only - note that max array element size is 4000 chars
979                        if (is_array($inputarr)) {
980                                $bindpos = $sql[3];
981                                if (isset($this->_bind[$bindpos])) {
982                                // all tied up already
983                                        $bindarr = &$this->_bind[$bindpos];
984                                } else {
985                                // one statement to bind them all
986                                        $bindarr = array();
987                                        foreach($inputarr as $k => $v) {
988                                                $bindarr[$k] = $v;
989                                                OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000);
990                                        }
991                                        $this->_bind[$bindpos] = &$bindarr;
992                                }
993                        }
994                } else {
995                        $stmt=OCIParse($this->_connectionID,$sql);
996                }
997                       
998                $this->_stmt = $stmt;
999                if (!$stmt) return false;
1000       
1001                if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
1002                       
1003                if (is_array($inputarr)) {
1004                        foreach($inputarr as $k => $v) {
1005                                if (is_array($v)) {
1006                                        if (sizeof($v) == 2) // suggested by g.giunta@libero.
1007                                                OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
1008                                        else
1009                                                OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
1010                                       
1011                                        if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
1012                                } else {
1013                                        $len = -1;
1014                                        if ($v === ' ') $len = 1;
1015                                        if (isset($bindarr)) {  // is prepared sql, so no need to ocibindbyname again
1016                                                $bindarr[$k] = $v;
1017                                        } else {                                // dynamic sql, so rebind every time
1018                                                OCIBindByName($stmt,":$k",$inputarr[$k],$len);
1019                                        }
1020                                }
1021                        }
1022                }
1023               
1024        $this->_errorMsg = false;
1025                $this->_errorCode = false;
1026                if (OCIExecute($stmt,$this->_commit)) {
1027//OCIInternalDebug(1);                 
1028                        if (count($this -> _refLOBs) > 0) {
1029               
1030                                foreach ($this -> _refLOBs as $key => $value) {
1031                                        if ($this -> _refLOBs[$key]['TYPE'] == true) {
1032                                                $tmp = $this -> _refLOBs[$key]['LOB'] -> load();
1033                                                if ($this -> debug) {
1034                                                        ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>");
1035                                                }
1036                                                //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp;
1037                                                $this -> _refLOBs[$key]['VAR'] = $tmp;
1038                                        } else {
1039                        $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']);
1040                                                $this -> _refLOBs[$key]['LOB']->free();
1041                                                unset($this -> _refLOBs[$key]);
1042                        if ($this->debug) {
1043                                                        ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>");
1044                                                }
1045                    }                                   
1046                                }
1047                        }
1048               
1049            switch (@OCIStatementType($stmt)) {
1050                case "SELECT":
1051                                        return $stmt;
1052                               
1053                                case 'DECLARE':
1054                case "BEGIN":
1055                    if (is_array($sql) && !empty($sql[4])) {
1056                                                $cursor = $sql[4];
1057                                                if (is_resource($cursor)) {
1058                                                        $ok = OCIExecute($cursor);     
1059                                return $cursor;
1060                                                }
1061                                                return $stmt;
1062                    } else {
1063                                                if (is_resource($stmt)) {
1064                                                        OCIFreeStatement($stmt);
1065                                                        return true;
1066                                                }
1067                        return $stmt;
1068                    }
1069                    break;
1070                default :
1071                                        // ociclose -- no because it could be used in a LOB?
1072                    return true;
1073            }
1074                }
1075                return false;
1076        }
1077       
1078        // returns true or false
1079        function _close()
1080        {
1081                if (!$this->_connectionID) return;
1082               
1083                if (!$this->autoCommit) OCIRollback($this->_connectionID);
1084                if (count($this->_refLOBs) > 0) {
1085                        foreach ($this ->_refLOBs as $key => $value) {
1086                                $this->_refLOBs[$key]['LOB']->free();
1087                                unset($this->_refLOBs[$key]);
1088                        }
1089                }
1090                OCILogoff($this->_connectionID);
1091               
1092                $this->_stmt = false;
1093                $this->_connectionID = false;
1094        }
1095       
1096        function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
1097        {
1098                if ($internalKey) return array('ROWID');
1099               
1100        // tested with oracle 8.1.7
1101                $table = strtoupper($table);
1102                if ($owner) {
1103                        $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
1104                        $ptab = 'ALL_';
1105                } else {
1106                        $owner_clause = '';
1107                        $ptab = 'USER_';
1108                }
1109                $sql = "
1110SELECT /*+ RULE */ distinct b.column_name
1111   FROM {$ptab}CONSTRAINTS a
1112          , {$ptab}CONS_COLUMNS b
1113  WHERE ( UPPER(b.table_name) = ('$table'))
1114        AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
1115        $owner_clause
1116        AND (a.constraint_name = b.constraint_name)";
1117
1118                $rs = $this->Execute($sql);
1119                if ($rs && !$rs->EOF) {
1120                        $arr =& $rs->GetArray();
1121                        $a = array();
1122                        foreach($arr as $v) {
1123                                $a[] = reset($v);
1124                        }
1125                        return $a;
1126                }
1127                else return false;
1128        }
1129       
1130        // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
1131        function MetaForeignKeys($table, $owner=false)
1132        {
1133        global $ADODB_FETCH_MODE;
1134       
1135                $save = $ADODB_FETCH_MODE;
1136                $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1137                $table = $this->qstr(strtoupper($table));
1138                if (!$owner) {
1139                        $owner = $this->user;
1140                        $tabp = 'user_';
1141                } else
1142                        $tabp = 'all_';
1143                       
1144                $owner = ' and owner='.$this->qstr(strtoupper($owner));
1145               
1146                $sql =
1147"select constraint_name,r_owner,r_constraint_name
1148        from {$tabp}constraints
1149        where constraint_type = 'R' and table_name = $table $owner";
1150               
1151                $constraints =& $this->GetArray($sql);
1152                $arr = false;
1153                foreach($constraints as $constr) {
1154                        $cons = $this->qstr($constr[0]);
1155                        $rowner = $this->qstr($constr[1]);
1156                        $rcons = $this->qstr($constr[2]);
1157                        $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
1158                        $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
1159                       
1160                        if ($cols && $tabcol)
1161                                for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
1162                                        $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
1163                                }
1164                }
1165                $ADODB_FETCH_MODE = $save;
1166               
1167                return $arr;
1168        }
1169
1170       
1171        function CharMax()
1172        {
1173                return 4000;
1174        }
1175       
1176        function TextMax()
1177        {
1178                return 4000;
1179        }
1180       
1181        /**
1182         * Quotes a string.
1183         * An example is  $db->qstr("Don't bother",magic_quotes_runtime());
1184         *
1185         * @param s                     the string to quote
1186         * @param [magic_quotes]        if $s is GET/POST var, set to get_magic_quotes_gpc().
1187         *                              This undoes the stupidity of magic quotes for GPC.
1188         *
1189         * @return  quoted string to be sent back to database
1190         */
1191        function qstr($s,$magic_quotes=false)
1192        {       
1193                //$nofixquotes=false;
1194       
1195                if ($this->noNullStrings && strlen($s)==0)$s = ' ';
1196                if (!$magic_quotes) {   
1197                        if ($this->replaceQuote[0] == '\\'){
1198                                $s = str_replace('\\','\\\\',$s);
1199                        }
1200                        return  "'".str_replace("'",$this->replaceQuote,$s)."'";
1201                }
1202               
1203                // undo magic quotes for "
1204                $s = str_replace('\\"','"',$s);
1205               
1206                $s = str_replace('\\\\','\\',$s);
1207                return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
1208               
1209        }
1210       
1211}
1212
1213/*--------------------------------------------------------------------------------------
1214                 Class Name: Recordset
1215--------------------------------------------------------------------------------------*/
1216
1217class ADORecordset_oci8 extends ADORecordSet {
1218
1219        var $databaseType = 'oci8';
1220        var $bind=false;
1221        var $_fieldobjs;
1222       
1223        //var $_arr = false;
1224               
1225        function ADORecordset_oci8($queryID,$mode=false)
1226        {
1227                if ($mode === false) {
1228                        global $ADODB_FETCH_MODE;
1229                        $mode = $ADODB_FETCH_MODE;
1230                }
1231                switch ($mode)
1232                {
1233                case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1234                case ADODB_FETCH_DEFAULT:
1235                case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1236                case ADODB_FETCH_NUM:
1237                default:
1238                $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1239                }
1240               
1241                $this->adodbFetchMode = $mode;
1242                $this->_queryID = $queryID;
1243        }
1244
1245
1246        function Init()
1247        {
1248                if ($this->_inited) return;
1249               
1250                $this->_inited = true;
1251                if ($this->_queryID) {
1252                       
1253                        $this->_currentRow = 0;
1254                        @$this->_initrs();
1255                        $this->EOF = !$this->_fetch();
1256                       
1257                        /*
1258                        // based on idea by Gaetano Giunta to detect unusual oracle errors
1259                        // see http://phplens.com/lens/lensforum/msgs.php?id=6771
1260                        $err = OCIError($this->_queryID);
1261                        if ($err && $this->connection->debug) ADOConnection::outp($err);
1262                        */
1263                       
1264                        if (!is_array($this->fields)) {
1265                                $this->_numOfRows = 0;
1266                                $this->fields = array();
1267                        }
1268                } else {
1269                        $this->fields = array();
1270                        $this->_numOfRows = 0;
1271                        $this->_numOfFields = 0;
1272                        $this->EOF = true;
1273                }
1274        }
1275       
1276        function _initrs()
1277        {
1278                $this->_numOfRows = -1;
1279                $this->_numOfFields = OCInumcols($this->_queryID);
1280                if ($this->_numOfFields>0) {
1281                        $this->_fieldobjs = array();
1282                        $max = $this->_numOfFields;
1283                        for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
1284                }
1285        }
1286
1287          /*            Returns: an object containing field information.
1288                          Get column information in the Recordset object. fetchField() can be used in order to obtain information about
1289                          fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
1290                          fetchField() is retrieved.            */
1291
1292        function &_FetchField($fieldOffset = -1)
1293        {
1294                $fld = new ADOFieldObject;
1295                $fieldOffset += 1;
1296                $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
1297                $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
1298                $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
1299                if ($fld->type == 'NUMBER') {
1300                        $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
1301                        $sc = OCIColumnScale($this->_queryID, $fieldOffset);
1302                        if ($p != 0 && $sc == 0) $fld->type = 'INT';
1303                        //echo " $this->name ($p.$sc) ";
1304                }
1305                return $fld;
1306        }
1307       
1308        /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
1309        function &FetchField($fieldOffset = -1)
1310        {
1311                return $this->_fieldobjs[$fieldOffset];
1312        }
1313       
1314       
1315        /*
1316        // 10% speedup to move MoveNext to child class
1317        function _MoveNext()
1318        {
1319        //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
1320               
1321                if ($this->EOF) return false;
1322               
1323                $this->_currentRow++;
1324                if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
1325                        return true;
1326                $this->EOF = true;
1327               
1328                return false;
1329        }       */
1330       
1331       
1332        function MoveNext()
1333        {
1334                if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
1335                        $this->_currentRow += 1;
1336                        return true;
1337                }
1338                if (!$this->EOF) {
1339                        $this->_currentRow += 1;
1340                        $this->EOF = true;
1341                }
1342                return false;
1343        }
1344       
1345        /*
1346        # does not work as first record is retrieved in _initrs(), so is not included in GetArray()
1347        function &GetArray($nRows = -1)
1348        {
1349        global $ADODB_OCI8_GETARRAY;
1350       
1351                if (true ||  !empty($ADODB_OCI8_GETARRAY)) {
1352                        # does not support $ADODB_ANSI_PADDING_OFF
1353       
1354                        //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement
1355                        switch($this->adodbFetchMode) {
1356                        case ADODB_FETCH_NUM:
1357                       
1358                                $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM);
1359                                $results = array_merge(array($this->fields),$results);
1360                                return $results;
1361                               
1362                        case ADODB_FETCH_ASSOC:
1363                                if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break;
1364                               
1365                                $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW);
1366                                $results =& array_merge(array($this->fields),$assoc);
1367                                return $results;
1368                       
1369                        default:
1370                                break;
1371                        }
1372                }
1373                       
1374                $results =& ADORecordSet::GetArray($nRows);
1375                return $results;
1376               
1377        } */
1378       
1379        /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
1380        function &GetArrayLimit($nrows,$offset=-1)
1381        {
1382                if ($offset <= 0) {
1383                        $arr =& $this->GetArray($nrows);
1384                        return $arr;
1385                }
1386                $arr = array();
1387                for ($i=1; $i < $offset; $i++)
1388                        if (!@OCIFetch($this->_queryID)) return $arr;
1389                       
1390                if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;;
1391                $results = array();
1392                $cnt = 0;
1393                while (!$this->EOF && $nrows != $cnt) {
1394                        $results[$cnt++] = $this->fields;
1395                        $this->MoveNext();
1396                }
1397               
1398                return $results;
1399        }
1400
1401       
1402        /* Use associative array to get fields array */
1403        function Fields($colname)
1404        {
1405                if (!$this->bind) {
1406                        $this->bind = array();
1407                        for ($i=0; $i < $this->_numOfFields; $i++) {
1408                                $o = $this->FetchField($i);
1409                                $this->bind[strtoupper($o->name)] = $i;
1410                        }
1411                }
1412               
1413                 return $this->fields[$this->bind[strtoupper($colname)]];
1414        }
1415       
1416
1417
1418        function _seek($row)
1419        {
1420                return false;
1421        }
1422
1423        function _fetch()
1424        {
1425                return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
1426        }
1427
1428        /*              close() only needs to be called if you are worried about using too much memory while your script
1429                        is running. All associated result memory for the specified result identifier will automatically be freed.               */
1430
1431        function _close()
1432        {
1433                if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
1434                if (!empty($this->_refcursor)) {
1435                        OCIFreeCursor($this->_refcursor);
1436                        $this->_refcursor = false;
1437                }
1438                @OCIFreeStatement($this->_queryID);
1439                $this->_queryID = false;
1440               
1441        }
1442
1443        function MetaType($t,$len=-1)
1444        {
1445                if (is_object($t)) {
1446                        $fieldobj = $t;
1447                        $t = $fieldobj->type;
1448                        $len = $fieldobj->max_length;
1449                }
1450                switch (strtoupper($t)) {
1451                case 'VARCHAR':
1452                case 'VARCHAR2':
1453                case 'CHAR':
1454                case 'VARBINARY':
1455                case 'BINARY':
1456                case 'NCHAR':
1457                case 'NVARCHAR':
1458                case 'NVARCHAR2':
1459                                 if (isset($this) && $len <= $this->blobSize) return 'C';
1460               
1461                case 'NCLOB':
1462                case 'LONG':
1463                case 'LONG VARCHAR':
1464                case 'CLOB':
1465                return 'X';
1466               
1467                case 'LONG RAW':
1468                case 'LONG VARBINARY':
1469                case 'BLOB':
1470                        return 'B';
1471               
1472                case 'DATE':
1473                        return  ($this->connection->datetime) ? 'T' : 'D';
1474               
1475               
1476                case 'TIMESTAMP': return 'T';
1477               
1478                case 'INT':
1479                case 'SMALLINT':
1480                case 'INTEGER':
1481                        return 'I';
1482                       
1483                default: return 'N';
1484                }
1485        }
1486}
1487
1488class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
1489        function ADORecordSet_ext_oci8($queryID,$mode=false)
1490        {
1491                if ($mode === false) {
1492                        global $ADODB_FETCH_MODE;
1493                        $mode = $ADODB_FETCH_MODE;
1494                }
1495                switch ($mode)
1496                {
1497                case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1498                case ADODB_FETCH_DEFAULT:
1499                case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1500                case ADODB_FETCH_NUM:
1501                default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1502                }
1503                $this->adodbFetchMode = $mode;
1504                $this->_queryID = $queryID;
1505        }
1506       
1507        function MoveNext()
1508        {
1509                return adodb_movenext($this);
1510        }
1511}
1512?>
Note: See TracBrowser for help on using the repository browser.