Merge commit 'catalyst/MOODLE_19_STABLE' into mdl19-linuxchix
[moodle-linuxchix.git] / lib / adodb / drivers / adodb-oci8.inc.php
blobb4b8e95c8b6af4016b5c9ab767e0957b2c1334a9
1 <?php
2 /*
4 version V4.98 13 Feb 2008 (c) 2000-2008 John Lim. All rights reserved.
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.
10 Latest version is available at http://adodb.sourceforge.net
12 Code contributed by George Fourlanos <fou@infomap.gr>
14 13 Nov 2000 jlim - removed all ora_* references.
17 // security - hide paths
18 if (!defined('ADODB_DIR')) die();
21 NLS_Date_Format
22 Allows you to use a date format other than the Oracle Lite default. When a literal
23 character string appears where a date value is expected, the Oracle Lite database
24 tests the string to see if it matches the formats of Oracle, SQL-92, or the value
25 specified for this parameter in the POLITE.INI file. Setting this parameter also
26 defines the default format used in the TO_CHAR or TO_DATE functions when no
27 other format string is supplied.
29 For Oracle the default is dd-mon-yy or dd-mon-yyyy, and for SQL-92 the default is
30 yy-mm-dd or yyyy-mm-dd.
32 Using 'RR' in the format forces two-digit years less than or equal to 49 to be
33 interpreted as years in the 21st century (2000–2049), and years over 50 as years in
34 the 20th century (1950–1999). Setting the RR format as the default for all two-digit
35 year entries allows you to become year-2000 compliant. For example:
36 NLS_DATE_FORMAT='RR-MM-DD'
38 You can also modify the date format using the ALTER SESSION command.
41 # define the LOB descriptor type for the given type
42 # returns false if no LOB descriptor
43 function 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;
52 return $result;
55 class 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 $dateformat = 'YYYY-MM-DD'; // for DBDate()
87 var $useDBDateFormatForTextInput=false;
88 var $datetime = false; // MetaType('DATE') returns 'D' (datetime==false) or 'T' (datetime == true)
89 var $_refLOBs = array();
91 // var $ansiOuter = true; // if oracle9
93 function ADODB_oci8()
95 $this->_hasOCIFetchStatement = ADODB_PHPVER >= 0x4200;
96 if (defined('ADODB_EXTENSION')) $this->rsPrefix .= 'ext_';
99 /* Function &MetaColumns($table) added by smondino@users.sourceforge.net*/
100 function &MetaColumns($table)
102 global $ADODB_FETCH_MODE;
104 $false = false;
105 $save = $ADODB_FETCH_MODE;
106 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
107 if ($this->fetchMode !== false) $savem = $this->SetFetchMode(false);
109 $rs = $this->Execute(sprintf($this->metaColumnsSQL,strtoupper($table)));
111 if (isset($savem)) $this->SetFetchMode($savem);
112 $ADODB_FETCH_MODE = $save;
113 if (!$rs) {
114 return $false;
116 $retarr = array();
117 while (!$rs->EOF) { //print_r($rs->fields);
118 $fld = new ADOFieldObject();
119 $fld->name = $rs->fields[0];
120 $fld->type = $rs->fields[1];
121 $fld->max_length = $rs->fields[2];
122 $fld->scale = $rs->fields[3];
123 if ($rs->fields[1] == 'NUMBER') {
124 if ($rs->fields[3] == 0) $fld->type = 'INT';
125 $fld->max_length = $rs->fields[4];
127 $fld->not_null = (strncmp($rs->fields[5], 'NOT',3) === 0);
128 $fld->binary = (strpos($fld->type,'BLOB') !== false);
129 $fld->default_value = $rs->fields[6];
131 if ($ADODB_FETCH_MODE == ADODB_FETCH_NUM) $retarr[] = $fld;
132 else $retarr[strtoupper($fld->name)] = $fld;
133 $rs->MoveNext();
135 $rs->Close();
136 if (empty($retarr))
137 return $false;
138 else
139 return $retarr;
142 function Time()
144 $rs =& $this->Execute("select TO_CHAR($this->sysTimeStamp,'YYYY-MM-DD HH24:MI:SS') from dual");
145 if ($rs && !$rs->EOF) return $this->UnixTimeStamp(reset($rs->fields));
147 return false;
152 Multiple modes of connection are supported:
154 a. Local Database
155 $conn->Connect(false,'scott','tiger');
157 b. From tnsnames.ora
158 $conn->Connect(false,'scott','tiger',$tnsname);
159 $conn->Connect($tnsname,'scott','tiger');
161 c. Server + service name
162 $conn->Connect($serveraddress,'scott,'tiger',$service_name);
164 d. Server + SID
165 $conn->connectSID = true;
166 $conn->Connect($serveraddress,'scott,'tiger',$SID);
169 Example TNSName:
170 ---------------
171 NATSOFT.DOMAIN =
172 (DESCRIPTION =
173 (ADDRESS_LIST =
174 (ADDRESS = (PROTOCOL = TCP)(HOST = kermit)(PORT = 1523))
176 (CONNECT_DATA =
177 (SERVICE_NAME = natsoft.domain)
181 There are 3 connection modes, 0 = non-persistent, 1 = persistent, 2 = force new connection
184 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename,$mode=0)
186 if (!function_exists('OCIPLogon')) return null;
189 $this->_errorMsg = false;
190 $this->_errorCode = false;
192 if($argHostname) { // added by Jorma Tuomainen <jorma.tuomainen@ppoy.fi>
193 if (empty($argDatabasename)) $argDatabasename = $argHostname;
194 else {
195 if(strpos($argHostname,":")) {
196 $argHostinfo=explode(":",$argHostname);
197 $argHostname=$argHostinfo[0];
198 $argHostport=$argHostinfo[1];
199 } else {
200 $argHostport = empty($this->port)? "1521" : $this->port;
203 if ($this->connectSID) {
204 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
205 .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))";
206 } else
207 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname
208 .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))";
212 //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>";
213 if ($mode==1) {
214 $this->_connectionID = ($this->charSet) ?
215 OCIPLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
217 OCIPLogon($argUsername,$argPassword, $argDatabasename)
219 if ($this->_connectionID && $this->autoRollback) OCIrollback($this->_connectionID);
220 } else if ($mode==2) {
221 $this->_connectionID = ($this->charSet) ?
222 OCINLogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
224 OCINLogon($argUsername,$argPassword, $argDatabasename);
226 } else {
227 $this->_connectionID = ($this->charSet) ?
228 OCILogon($argUsername,$argPassword, $argDatabasename,$this->charSet)
230 OCILogon($argUsername,$argPassword, $argDatabasename);
232 if (!$this->_connectionID) return false;
233 if ($this->_initdate) {
234 $this->Execute("ALTER SESSION SET NLS_DATE_FORMAT='".$this->NLS_DATE_FORMAT."'");
237 // looks like:
238 // Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production With the Partitioning option JServer Release 8.1.7.0.0 - Production
239 // $vers = OCIServerVersion($this->_connectionID);
240 // if (strpos($vers,'8i') !== false) $this->ansiOuter = true;
241 return true;
244 function ServerInfo()
246 $arr['compat'] = $this->GetOne('select value from sys.database_compatible_level');
247 $arr['description'] = @OCIServerVersion($this->_connectionID);
248 $arr['version'] = ADOConnection::_findvers($arr['description']);
249 return $arr;
251 // returns true or false
252 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
254 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,1);
257 // returns true or false
258 function _nconnect($argHostname, $argUsername, $argPassword, $argDatabasename)
260 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename,2);
263 function _affectedrows()
265 if (is_resource($this->_stmt)) return @OCIRowCount($this->_stmt);
266 return 0;
269 function IfNull( $field, $ifNull )
271 return " NVL($field, $ifNull) "; // if Oracle
274 // format and return date string in database date format
275 function DBDate($d)
277 if (empty($d) && $d !== 0) return 'null';
279 if (is_string($d)) $d = ADORecordSet::UnixDate($d);
280 return "TO_DATE(".adodb_date($this->fmtDate,$d).",'".$this->dateformat."')";
283 function BindDate($d)
285 $d = ADOConnection::DBDate($d);
286 if (strncmp($d,"'",1)) return $d;
288 return substr($d,1,strlen($d)-2);
291 function BindTimeStamp($d)
293 $d = ADOConnection::DBTimeStamp($d);
294 if (strncmp($d,"'",1)) return $d;
296 return substr($d,1,strlen($d)-2);
299 // format and return date string in database timestamp format
300 function DBTimeStamp($ts)
302 if (empty($ts) && $ts !== 0) return 'null';
303 if (is_string($ts)) $ts = ADORecordSet::UnixTimeStamp($ts);
304 return 'TO_DATE('.adodb_date("'Y-m-d H:i:s'",$ts).",'RRRR-MM-DD, HH24:MI:SS')";
307 function RowLock($tables,$where,$flds='1 as ignore')
309 if ($this->autoCommit) $this->BeginTrans();
310 return $this->GetOne("select $flds from $tables where $where for update");
313 function &MetaTables($ttype=false,$showSchema=false,$mask=false)
315 if ($mask) {
316 $save = $this->metaTablesSQL;
317 $mask = $this->qstr(strtoupper($mask));
318 $this->metaTablesSQL .= " AND upper(table_name) like $mask";
320 $ret =& ADOConnection::MetaTables($ttype,$showSchema);
322 if ($mask) {
323 $this->metaTablesSQL = $save;
325 return $ret;
328 // Mark Newnham
329 function &MetaIndexes ($table, $primary = FALSE, $owner=false)
331 // save old fetch mode
332 global $ADODB_FETCH_MODE;
334 $save = $ADODB_FETCH_MODE;
335 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
337 if ($this->fetchMode !== FALSE) {
338 $savem = $this->SetFetchMode(FALSE);
341 // get index details
342 $table = strtoupper($table);
344 // get Primary index
345 $primary_key = '';
347 $false = false;
348 $rs = $this->Execute(sprintf("SELECT * FROM ALL_CONSTRAINTS WHERE UPPER(TABLE_NAME)='%s' AND CONSTRAINT_TYPE='P'",$table));
349 if ($row = $rs->FetchRow())
350 $primary_key = $row[1]; //constraint_name
352 if ($primary==TRUE && $primary_key=='') {
353 if (isset($savem))
354 $this->SetFetchMode($savem);
355 $ADODB_FETCH_MODE = $save;
356 return $false; //There is no primary key
359 $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));
362 if (!is_object($rs)) {
363 if (isset($savem))
364 $this->SetFetchMode($savem);
365 $ADODB_FETCH_MODE = $save;
366 return $false;
369 $indexes = array ();
370 // parse index data into array
372 while ($row = $rs->FetchRow()) {
373 if ($primary && $row[0] != $primary_key) continue;
374 if (!isset($indexes[$row[0]])) {
375 $indexes[$row[0]] = array(
376 'unique' => ($row[1] == 'UNIQUE'),
377 'columns' => array()
380 $indexes[$row[0]]['columns'][$row[2] - 1] = $row[3];
383 // sort columns by order in the index
384 foreach ( array_keys ($indexes) as $index ) {
385 ksort ($indexes[$index]['columns']);
388 if (isset($savem)) {
389 $this->SetFetchMode($savem);
390 $ADODB_FETCH_MODE = $save;
392 return $indexes;
395 function BeginTrans()
397 if ($this->transOff) return true;
398 $this->transCnt += 1;
399 $this->autoCommit = false;
400 $this->_commit = OCI_DEFAULT;
402 if ($this->_transmode) $this->Execute("SET TRANSACTION ".$this->_transmode);
403 return true;
406 function CommitTrans($ok=true)
408 if ($this->transOff) return true;
409 if (!$ok) return $this->RollbackTrans();
411 if ($this->transCnt) $this->transCnt -= 1;
412 $ret = OCIcommit($this->_connectionID);
413 $this->_commit = OCI_COMMIT_ON_SUCCESS;
414 $this->autoCommit = true;
415 return $ret;
418 function RollbackTrans()
420 if ($this->transOff) return true;
421 if ($this->transCnt) $this->transCnt -= 1;
422 $ret = OCIrollback($this->_connectionID);
423 $this->_commit = OCI_COMMIT_ON_SUCCESS;
424 $this->autoCommit = true;
425 return $ret;
429 function SelectDB($dbName)
431 return false;
434 function ErrorMsg()
436 if ($this->_errorMsg !== false) return $this->_errorMsg;
438 if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
439 if (empty($arr)) {
440 if (is_resource($this->_connectionID)) $arr = @OCIError($this->_connectionID);
441 else $arr = @OCIError();
442 if ($arr === false) return '';
444 $this->_errorMsg = $arr['message'];
445 $this->_errorCode = $arr['code'];
446 return $this->_errorMsg;
449 function ErrorNo()
451 if ($this->_errorCode !== false) return $this->_errorCode;
453 if (is_resource($this->_stmt)) $arr = @OCIError($this->_stmt);
454 if (empty($arr)) {
455 $arr = @OCIError($this->_connectionID);
456 if ($arr == false) $arr = @OCIError();
457 if ($arr == false) return '';
460 $this->_errorMsg = $arr['message'];
461 $this->_errorCode = $arr['code'];
463 return $arr['code'];
466 // Format date column in sql string given an input format that understands Y M D
467 function SQLDate($fmt, $col=false)
469 if (!$col) $col = $this->sysTimeStamp;
470 $s = 'TO_CHAR('.$col.",'";
472 $len = strlen($fmt);
473 for ($i=0; $i < $len; $i++) {
474 $ch = $fmt[$i];
475 switch($ch) {
476 case 'Y':
477 case 'y':
478 $s .= 'YYYY';
479 break;
480 case 'Q':
481 case 'q':
482 $s .= 'Q';
483 break;
485 case 'M':
486 $s .= 'Mon';
487 break;
489 case 'm':
490 $s .= 'MM';
491 break;
492 case 'D':
493 case 'd':
494 $s .= 'DD';
495 break;
497 case 'H':
498 $s.= 'HH24';
499 break;
501 case 'h':
502 $s .= 'HH';
503 break;
505 case 'i':
506 $s .= 'MI';
507 break;
509 case 's':
510 $s .= 'SS';
511 break;
513 case 'a':
514 case 'A':
515 $s .= 'AM';
516 break;
518 case 'w':
519 $s .= 'D';
520 break;
522 case 'l':
523 $s .= 'DAY';
524 break;
526 case 'W':
527 $s .= 'WW';
528 break;
530 default:
531 // handle escape characters...
532 if ($ch == '\\') {
533 $i++;
534 $ch = substr($fmt,$i,1);
536 if (strpos('-/.:;, ',$ch) !== false) $s .= $ch;
537 else $s .= '"'.$ch.'"';
541 return $s. "')";
544 function GetRandRow($sql, $arr = false)
546 $sql = "SELECT * FROM ($sql ORDER BY dbms_random.value) WHERE rownum = 1";
548 return $this->GetRow($sql,$arr);
552 This algorithm makes use of
554 a. FIRST_ROWS hint
555 The FIRST_ROWS hint explicitly chooses the approach to optimize response time,
556 that is, minimum resource usage to return the first row. Results will be returned
557 as soon as they are identified.
559 b. Uses rownum tricks to obtain only the required rows from a given offset.
560 As this uses complicated sql statements, we only use this if the $offset >= 100.
561 This idea by Tomas V V Cox.
563 This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
564 out this function then, and the slower SelectLimit() in the base class will be used.
566 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
568 // seems that oracle only supports 1 hint comment in 8i
569 if ($this->firstrows) {
570 if (strpos($sql,'/*+') !== false)
571 $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
572 else
573 $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
576 if ($offset < $this->selectOffsetAlg1 && 0 < $nrows && $nrows < 1000) {
577 if ($nrows > 0) {
578 if ($offset > 0) $nrows += $offset;
579 //$inputarr['adodb_rownum'] = $nrows;
580 if ($this->databaseType == 'oci8po') {
581 $sql = "select * from (".$sql.") where rownum <= ?";
582 } else {
583 $sql = "select * from (".$sql.") where rownum <= :adodb_offset";
585 $inputarr['adodb_offset'] = $nrows;
586 $nrows = -1;
588 // note that $nrows = 0 still has to work ==> no rows returned
590 $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
591 return $rs;
593 } else {
594 // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
596 // Let Oracle return the name of the columns
597 $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL";
599 $false = false;
600 if (! $stmt_arr = $this->Prepare($q_fields)) {
601 return $false;
603 $stmt = $stmt_arr[1];
605 if (is_array($inputarr)) {
606 foreach($inputarr as $k => $v) {
607 if (is_array($v)) {
608 if (sizeof($v) == 2) // suggested by g.giunta@libero.
609 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
610 else
611 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
612 } else {
613 $len = -1;
614 if ($v === ' ') $len = 1;
615 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
616 $bindarr[$k] = $v;
617 } else { // dynamic sql, so rebind every time
618 OCIBindByName($stmt,":$k",$inputarr[$k],$len);
624 if (!OCIExecute($stmt, OCI_DEFAULT)) {
625 OCIFreeStatement($stmt);
626 return $false;
629 $ncols = OCINumCols($stmt);
630 for ( $i = 1; $i <= $ncols; $i++ ) {
631 $cols[] = '"'.OCIColumnName($stmt, $i).'"';
633 $result = false;
635 OCIFreeStatement($stmt);
636 $fields = implode(',', $cols);
637 $nrows += $offset;
638 $offset += 1; // in Oracle rownum starts at 1
640 if ($this->databaseType == 'oci8po') {
641 $sql = "SELECT $fields FROM".
642 "(SELECT rownum as adodb_rownum, $fields FROM".
643 " ($sql) WHERE rownum <= ?".
644 ") WHERE adodb_rownum >= ?";
645 } else {
646 $sql = "SELECT $fields FROM".
647 "(SELECT rownum as adodb_rownum, $fields FROM".
648 " ($sql) WHERE rownum <= :adodb_nrows".
649 ") WHERE adodb_rownum >= :adodb_offset";
651 $inputarr['adodb_nrows'] = $nrows;
652 $inputarr['adodb_offset'] = $offset;
654 if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr);
655 else $rs =& $this->Execute($sql,$inputarr);
656 return $rs;
662 * Usage:
663 * Store BLOBs and CLOBs
665 * Example: to store $var in a blob
667 * $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
668 * $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
670 * $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
672 * to get length of LOB:
673 * select DBMS_LOB.GETLENGTH(ablob) from TABLE
675 * If you are using CURSOR_SHARING = force, it appears this will case a segfault
676 * under oracle 8.1.7.0. Run:
677 * $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
678 * before UpdateBlob() then...
681 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
684 //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
686 switch(strtoupper($blobtype)) {
687 default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
688 case 'BLOB': $type = OCI_B_BLOB; break;
689 case 'CLOB': $type = OCI_B_CLOB; break;
692 if ($this->databaseType == 'oci8po')
693 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
694 else
695 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
697 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
698 $arr['blob'] = array($desc,-1,$type);
699 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
700 $commit = $this->autoCommit;
701 if ($commit) $this->BeginTrans();
702 $rs = $this->_Execute($sql,$arr);
703 if ($rez = !empty($rs)) $desc->save($val);
704 $desc->free();
705 if ($commit) $this->CommitTrans();
706 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
708 if ($rez) $rs->Close();
709 return $rez;
713 * Usage: store file pointed to by $var in a blob
715 function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
717 switch(strtoupper($blobtype)) {
718 default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
719 case 'BLOB': $type = OCI_B_BLOB; break;
720 case 'CLOB': $type = OCI_B_CLOB; break;
723 if ($this->databaseType == 'oci8po')
724 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
725 else
726 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
728 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
729 $arr['blob'] = array($desc,-1,$type);
731 $this->BeginTrans();
732 $rs = ADODB_oci8::Execute($sql,$arr);
733 if ($rez = !empty($rs)) $desc->savefile($val);
734 $desc->free();
735 $this->CommitTrans();
737 if ($rez) $rs->Close();
738 return $rez;
742 * Execute SQL
744 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
745 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
746 * @return RecordSet or false
748 function &Execute($sql,$inputarr=false)
750 if ($this->fnExecute) {
751 $fn = $this->fnExecute;
752 $ret =& $fn($this,$sql,$inputarr);
753 if (isset($ret)) return $ret;
755 if ($inputarr) {
756 #if (!is_array($inputarr)) $inputarr = array($inputarr);
757 $element0 = reset($inputarr);
759 # is_object check because oci8 descriptors can be passed in
760 if (is_array($element0) && !is_object(reset($element0))) {
761 if (is_string($sql))
762 $stmt = $this->Prepare($sql);
763 else
764 $stmt = $sql;
766 foreach($inputarr as $arr) {
767 $ret =& $this->_Execute($stmt,$arr);
768 if (!$ret) return $ret;
770 } else {
771 $ret =& $this->_Execute($sql,$inputarr);
774 } else {
775 $ret =& $this->_Execute($sql,false);
778 return $ret;
782 Example of usage:
784 $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
786 function Prepare($sql,$cursor=false)
788 static $BINDNUM = 0;
790 $stmt = OCIParse($this->_connectionID,$sql);
792 if (!$stmt) {
793 $this->_errorMsg = false;
794 $this->_errorCode = false;
795 $arr = @OCIError($this->_connectionID);
796 if ($arr === false) return false;
798 $this->_errorMsg = $arr['message'];
799 $this->_errorCode = $arr['code'];
800 return false;
803 $BINDNUM += 1;
805 $sttype = @OCIStatementType($stmt);
806 if ($sttype == 'BEGIN' || $sttype == 'DECLARE') {
807 return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
809 return array($sql,$stmt,0,$BINDNUM);
813 Call an oracle stored procedure and returns a cursor variable as a recordset.
814 Concept by Robert Tuttle robert@ud.com
816 Example:
817 Note: we return a cursor variable in :RS2
818 $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
820 $rs = $db->ExecuteCursor(
821 "BEGIN :RS2 = adodb.getdata(:VAR1); END;",
822 'RS2',
823 array('VAR1' => 'Mr Bean'));
826 function &ExecuteCursor($sql,$cursorName='rs',$params=false)
828 if (is_array($sql)) $stmt = $sql;
829 else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
831 if (is_array($stmt) && sizeof($stmt) >= 5) {
832 $hasref = true;
833 $ignoreCur = false;
834 $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
835 if ($params) {
836 foreach($params as $k => $v) {
837 $this->Parameter($stmt,$params[$k], $k);
840 } else
841 $hasref = false;
843 $rs =& $this->Execute($stmt);
844 if ($rs) {
845 if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]);
846 else if ($hasref) $rs->_refcursor = $stmt[4];
848 return $rs;
852 Bind a variable -- very, very fast for executing repeated statements in oracle.
853 Better than using
854 for ($i = 0; $i < $max; $i++) {
855 $p1 = ?; $p2 = ?; $p3 = ?;
856 $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)",
857 array($p1,$p2,$p3));
860 Usage:
861 $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
862 $DB->Bind($stmt, $p1);
863 $DB->Bind($stmt, $p2);
864 $DB->Bind($stmt, $p3);
865 for ($i = 0; $i < $max; $i++) {
866 $p1 = ?; $p2 = ?; $p3 = ?;
867 $DB->Execute($stmt);
870 Some timings:
871 ** Test table has 3 cols, and 1 index. Test to insert 1000 records
872 Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
873 Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
874 Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
876 Now if PHP only had batch/bulk updating like Java or PL/SQL...
878 Note that the order of parameters differs from OCIBindByName,
879 because we default the names to :0, :1, :2
881 function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false)
884 if (!is_array($stmt)) return false;
886 if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) {
887 return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
890 if ($name == false) {
891 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type);
892 else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
893 $stmt[2] += 1;
894 } else if (oci_lob_desc($type)) {
895 if ($this->debug) {
896 ADOConnection::outp("<b>Bind</b>: name = $name");
898 //we have to create a new Descriptor here
899 $numlob = count($this->_refLOBs);
900 $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type));
901 $this->_refLOBs[$numlob]['TYPE'] = $isOutput;
903 $tmp = &$this->_refLOBs[$numlob]['LOB'];
904 $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type);
905 if ($this->debug) {
906 ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded");
909 // if type is input then write data to lob now
910 if ($isOutput == false) {
911 $var = $this->BlobEncode($var);
912 $tmp->WriteTemporary($var);
913 $this->_refLOBs[$numlob]['VAR'] = &$var;
914 if ($this->debug) {
915 ADOConnection::outp("<b>Bind</b>: LOB has been written to temp");
917 } else {
918 $this->_refLOBs[$numlob]['VAR'] = &$var;
920 $rez = $tmp;
921 } else {
922 if ($this->debug)
923 ADOConnection::outp("<b>Bind</b>: name = $name");
925 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
926 else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
929 return $rez;
932 function Param($name,$type=false)
934 return ':'.$name;
938 Usage:
939 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
940 $db->Parameter($stmt,$id,'myid');
941 $db->Parameter($stmt,$group,'group');
942 $db->Execute($stmt);
944 @param $stmt Statement returned by Prepare() or PrepareSP().
945 @param $var PHP variable to bind to
946 @param $name Name of stored procedure variable name to bind to.
947 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
948 @param [$maxLen] Holds an maximum length of the variable.
949 @param [$type] The data type of $var. Legal values depend on driver.
951 See OCIBindByName documentation at php.net.
953 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
955 if ($this->debug) {
956 $prefix = ($isOutput) ? 'Out' : 'In';
957 $ztype = (empty($type)) ? 'false' : $type;
958 ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
960 return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput);
964 returns query ID if successful, otherwise false
965 this version supports:
967 1. $db->execute('select * from table');
969 2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
970 $db->execute($prepared_statement, array(1,2,3));
972 3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
974 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
975 $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3);
976 $db->execute($stmt);
978 function _query($sql,$inputarr)
980 if (is_array($sql)) { // is prepared sql
981 $stmt = $sql[1];
983 // we try to bind to permanent array, so that OCIBindByName is persistent
984 // and carried out once only - note that max array element size is 4000 chars
985 if (is_array($inputarr)) {
986 $bindpos = $sql[3];
987 if (isset($this->_bind[$bindpos])) {
988 // all tied up already
989 $bindarr = &$this->_bind[$bindpos];
990 } else {
991 // one statement to bind them all
992 $bindarr = array();
993 foreach($inputarr as $k => $v) {
994 $bindarr[$k] = $v;
995 OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000);
997 $this->_bind[$bindpos] = &$bindarr;
1000 } else {
1001 $stmt=OCIParse($this->_connectionID,$sql);
1004 $this->_stmt = $stmt;
1005 if (!$stmt) return false;
1007 if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
1009 if (is_array($inputarr)) {
1010 foreach($inputarr as $k => $v) {
1011 if (is_array($v)) {
1012 if (sizeof($v) == 2) // suggested by g.giunta@libero.
1013 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
1014 else
1015 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
1017 if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
1018 } else {
1019 $len = -1;
1020 if ($v === ' ') $len = 1;
1021 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
1022 $bindarr[$k] = $v;
1023 } else { // dynamic sql, so rebind every time
1024 OCIBindByName($stmt,":$k",$inputarr[$k],$len);
1030 $this->_errorMsg = false;
1031 $this->_errorCode = false;
1032 if (OCIExecute($stmt,$this->_commit)) {
1033 //OCIInternalDebug(1);
1034 if (count($this -> _refLOBs) > 0) {
1036 foreach ($this -> _refLOBs as $key => $value) {
1037 if ($this -> _refLOBs[$key]['TYPE'] == true) {
1038 $tmp = $this -> _refLOBs[$key]['LOB'] -> load();
1039 if ($this -> debug) {
1040 ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>");
1042 //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp;
1043 $this -> _refLOBs[$key]['VAR'] = $tmp;
1044 } else {
1045 $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']);
1046 $this -> _refLOBs[$key]['LOB']->free();
1047 unset($this -> _refLOBs[$key]);
1048 if ($this->debug) {
1049 ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>");
1055 switch (@OCIStatementType($stmt)) {
1056 case "SELECT":
1057 return $stmt;
1059 case 'DECLARE':
1060 case "BEGIN":
1061 if (is_array($sql) && !empty($sql[4])) {
1062 $cursor = $sql[4];
1063 if (is_resource($cursor)) {
1064 $ok = OCIExecute($cursor);
1065 return $cursor;
1067 return $stmt;
1068 } else {
1069 if (is_resource($stmt)) {
1070 OCIFreeStatement($stmt);
1071 return true;
1073 return $stmt;
1075 break;
1076 default :
1077 // ociclose -- no because it could be used in a LOB?
1078 return true;
1081 return false;
1084 // returns true or false
1085 function _close()
1087 if (!$this->_connectionID) return;
1089 if (!$this->autoCommit) OCIRollback($this->_connectionID);
1090 if (count($this->_refLOBs) > 0) {
1091 foreach ($this ->_refLOBs as $key => $value) {
1092 $this->_refLOBs[$key]['LOB']->free();
1093 unset($this->_refLOBs[$key]);
1096 OCILogoff($this->_connectionID);
1098 $this->_stmt = false;
1099 $this->_connectionID = false;
1102 function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
1104 if ($internalKey) return array('ROWID');
1106 // tested with oracle 8.1.7
1107 $table = strtoupper($table);
1108 if ($owner) {
1109 $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
1110 $ptab = 'ALL_';
1111 } else {
1112 $owner_clause = '';
1113 $ptab = 'USER_';
1115 $sql = "
1116 SELECT /*+ RULE */ distinct b.column_name
1117 FROM {$ptab}CONSTRAINTS a
1118 , {$ptab}CONS_COLUMNS b
1119 WHERE ( UPPER(b.table_name) = ('$table'))
1120 AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
1121 $owner_clause
1122 AND (a.constraint_name = b.constraint_name)";
1124 $rs = $this->Execute($sql);
1125 if ($rs && !$rs->EOF) {
1126 $arr =& $rs->GetArray();
1127 $a = array();
1128 foreach($arr as $v) {
1129 $a[] = reset($v);
1131 return $a;
1133 else return false;
1136 // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
1137 function MetaForeignKeys($table, $owner=false)
1139 global $ADODB_FETCH_MODE;
1141 $save = $ADODB_FETCH_MODE;
1142 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1143 $table = $this->qstr(strtoupper($table));
1144 if (!$owner) {
1145 $owner = $this->user;
1146 $tabp = 'user_';
1147 } else
1148 $tabp = 'all_';
1150 $owner = ' and owner='.$this->qstr(strtoupper($owner));
1152 $sql =
1153 "select constraint_name,r_owner,r_constraint_name
1154 from {$tabp}constraints
1155 where constraint_type = 'R' and table_name = $table $owner";
1157 $constraints =& $this->GetArray($sql);
1158 $arr = false;
1159 foreach($constraints as $constr) {
1160 $cons = $this->qstr($constr[0]);
1161 $rowner = $this->qstr($constr[1]);
1162 $rcons = $this->qstr($constr[2]);
1163 $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
1164 $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
1166 if ($cols && $tabcol)
1167 for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
1168 $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
1171 $ADODB_FETCH_MODE = $save;
1173 return $arr;
1177 function CharMax()
1179 return 4000;
1182 function TextMax()
1184 return 4000;
1188 * Quotes a string.
1189 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
1191 * @param s the string to quote
1192 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
1193 * This undoes the stupidity of magic quotes for GPC.
1195 * @return quoted string to be sent back to database
1197 function qstr($s,$magic_quotes=false)
1199 //$nofixquotes=false;
1201 if ($this->noNullStrings && strlen($s)==0)$s = ' ';
1202 if (!$magic_quotes) {
1203 if ($this->replaceQuote[0] == '\\'){
1204 $s = str_replace('\\','\\\\',$s);
1206 return "'".str_replace("'",$this->replaceQuote,$s)."'";
1209 // undo magic quotes for "
1210 $s = str_replace('\\"','"',$s);
1212 $s = str_replace('\\\\','\\',$s);
1213 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
1219 /*--------------------------------------------------------------------------------------
1220 Class Name: Recordset
1221 --------------------------------------------------------------------------------------*/
1223 class ADORecordset_oci8 extends ADORecordSet {
1225 var $databaseType = 'oci8';
1226 var $bind=false;
1227 var $_fieldobjs;
1229 //var $_arr = false;
1231 function ADORecordset_oci8($queryID,$mode=false)
1233 if ($mode === false) {
1234 global $ADODB_FETCH_MODE;
1235 $mode = $ADODB_FETCH_MODE;
1237 switch ($mode)
1239 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1240 case ADODB_FETCH_DEFAULT:
1241 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1242 case ADODB_FETCH_NUM:
1243 default:
1244 $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1247 $this->adodbFetchMode = $mode;
1248 $this->_queryID = $queryID;
1252 function Init()
1254 if ($this->_inited) return;
1256 $this->_inited = true;
1257 if ($this->_queryID) {
1259 $this->_currentRow = 0;
1260 @$this->_initrs();
1261 $this->EOF = !$this->_fetch();
1264 // based on idea by Gaetano Giunta to detect unusual oracle errors
1265 // see http://phplens.com/lens/lensforum/msgs.php?id=6771
1266 $err = OCIError($this->_queryID);
1267 if ($err && $this->connection->debug) ADOConnection::outp($err);
1270 if (!is_array($this->fields)) {
1271 $this->_numOfRows = 0;
1272 $this->fields = array();
1274 } else {
1275 $this->fields = array();
1276 $this->_numOfRows = 0;
1277 $this->_numOfFields = 0;
1278 $this->EOF = true;
1282 function _initrs()
1284 $this->_numOfRows = -1;
1285 $this->_numOfFields = OCInumcols($this->_queryID);
1286 if ($this->_numOfFields>0) {
1287 $this->_fieldobjs = array();
1288 $max = $this->_numOfFields;
1289 for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
1293 /* Returns: an object containing field information.
1294 Get column information in the Recordset object. fetchField() can be used in order to obtain information about
1295 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
1296 fetchField() is retrieved. */
1298 function _FetchField($fieldOffset = -1)
1300 $fld = new ADOFieldObject;
1301 $fieldOffset += 1;
1302 $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
1303 $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
1304 $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
1305 switch($fld->type) {
1306 case 'NUMBER':
1307 $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
1308 $sc = OCIColumnScale($this->_queryID, $fieldOffset);
1309 if ($p != 0 && $sc == 0) $fld->type = 'INT';
1310 break;
1312 case 'CLOB':
1313 case 'NCLOB':
1314 case 'BLOB':
1315 $fld->max_length = -1;
1316 break;
1318 return $fld;
1321 /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
1322 function &FetchField($fieldOffset = -1)
1324 return $this->_fieldobjs[$fieldOffset];
1329 // 10% speedup to move MoveNext to child class
1330 function _MoveNext()
1332 //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
1334 if ($this->EOF) return false;
1336 $this->_currentRow++;
1337 if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
1338 return true;
1339 $this->EOF = true;
1341 return false;
1342 } */
1345 function MoveNext()
1347 if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
1348 $this->_currentRow += 1;
1349 return true;
1351 if (!$this->EOF) {
1352 $this->_currentRow += 1;
1353 $this->EOF = true;
1355 return false;
1359 # does not work as first record is retrieved in _initrs(), so is not included in GetArray()
1360 function &GetArray($nRows = -1)
1362 global $ADODB_OCI8_GETARRAY;
1364 if (true || !empty($ADODB_OCI8_GETARRAY)) {
1365 # does not support $ADODB_ANSI_PADDING_OFF
1367 //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement
1368 switch($this->adodbFetchMode) {
1369 case ADODB_FETCH_NUM:
1371 $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM);
1372 $results = array_merge(array($this->fields),$results);
1373 return $results;
1375 case ADODB_FETCH_ASSOC:
1376 if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break;
1378 $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW);
1379 $results =& array_merge(array($this->fields),$assoc);
1380 return $results;
1382 default:
1383 break;
1387 $results =& ADORecordSet::GetArray($nRows);
1388 return $results;
1390 } */
1392 /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
1393 function &GetArrayLimit($nrows,$offset=-1)
1395 if ($offset <= 0) {
1396 $arr =& $this->GetArray($nrows);
1397 return $arr;
1399 $arr = array();
1400 for ($i=1; $i < $offset; $i++)
1401 if (!@OCIFetch($this->_queryID)) return $arr;
1403 if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;;
1404 $results = array();
1405 $cnt = 0;
1406 while (!$this->EOF && $nrows != $cnt) {
1407 $results[$cnt++] = $this->fields;
1408 $this->MoveNext();
1411 return $results;
1415 /* Use associative array to get fields array */
1416 function Fields($colname)
1418 if (!$this->bind) {
1419 $this->bind = array();
1420 for ($i=0; $i < $this->_numOfFields; $i++) {
1421 $o = $this->FetchField($i);
1422 $this->bind[strtoupper($o->name)] = $i;
1426 return $this->fields[$this->bind[strtoupper($colname)]];
1431 function _seek($row)
1433 return false;
1436 function _fetch()
1438 return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
1441 /* close() only needs to be called if you are worried about using too much memory while your script
1442 is running. All associated result memory for the specified result identifier will automatically be freed. */
1444 function _close()
1446 if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
1447 if (!empty($this->_refcursor)) {
1448 OCIFreeCursor($this->_refcursor);
1449 $this->_refcursor = false;
1451 @OCIFreeStatement($this->_queryID);
1452 $this->_queryID = false;
1456 function MetaType($t,$len=-1)
1458 if (is_object($t)) {
1459 $fieldobj = $t;
1460 $t = $fieldobj->type;
1461 $len = $fieldobj->max_length;
1463 switch (strtoupper($t)) {
1464 case 'VARCHAR':
1465 case 'VARCHAR2':
1466 case 'CHAR':
1467 case 'VARBINARY':
1468 case 'BINARY':
1469 case 'NCHAR':
1470 case 'NVARCHAR':
1471 case 'NVARCHAR2':
1472 if (isset($this) && $len <= $this->blobSize) return 'C';
1474 case 'NCLOB':
1475 case 'LONG':
1476 case 'LONG VARCHAR':
1477 case 'CLOB':
1478 return 'X';
1480 case 'LONG RAW':
1481 case 'LONG VARBINARY':
1482 case 'BLOB':
1483 return 'B';
1485 case 'DATE':
1486 return ($this->connection->datetime) ? 'T' : 'D';
1489 case 'TIMESTAMP': return 'T';
1491 case 'INT':
1492 case 'SMALLINT':
1493 case 'INTEGER':
1494 return 'I';
1496 default: return 'N';
1501 class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
1502 function ADORecordSet_ext_oci8($queryID,$mode=false)
1504 if ($mode === false) {
1505 global $ADODB_FETCH_MODE;
1506 $mode = $ADODB_FETCH_MODE;
1508 switch ($mode)
1510 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1511 case ADODB_FETCH_DEFAULT:
1512 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1513 case ADODB_FETCH_NUM:
1514 default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1516 $this->adodbFetchMode = $mode;
1517 $this->_queryID = $queryID;
1520 function MoveNext()
1522 return adodb_movenext($this);