MDL-11517 reserved word MOD used in table alias in questions backup code
[moodle-pu.git] / lib / adodb / drivers / adodb-oci8.inc.php
blobb86c10b781cfd0508a0b550511478a9cc099c43c
1 <?php
2 /*
4 version V4.94 23 Jan 2007 (c) 2000-2007 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. "')";
546 This algorithm makes use of
548 a. FIRST_ROWS hint
549 The FIRST_ROWS hint explicitly chooses the approach to optimize response time,
550 that is, minimum resource usage to return the first row. Results will be returned
551 as soon as they are identified.
553 b. Uses rownum tricks to obtain only the required rows from a given offset.
554 As this uses complicated sql statements, we only use this if the $offset >= 100.
555 This idea by Tomas V V Cox.
557 This implementation does not appear to work with oracle 8.0.5 or earlier. Comment
558 out this function then, and the slower SelectLimit() in the base class will be used.
560 function &SelectLimit($sql,$nrows=-1,$offset=-1, $inputarr=false,$secs2cache=0)
562 // seems that oracle only supports 1 hint comment in 8i
563 if ($this->firstrows) {
564 if (strpos($sql,'/*+') !== false)
565 $sql = str_replace('/*+ ','/*+FIRST_ROWS ',$sql);
566 else
567 $sql = preg_replace('/^[ \t\n]*select/i','SELECT /*+FIRST_ROWS*/',$sql);
570 if ($offset < $this->selectOffsetAlg1) {
571 if ($nrows > 0) {
572 if ($offset > 0) $nrows += $offset;
573 //$inputarr['adodb_rownum'] = $nrows;
574 if ($this->databaseType == 'oci8po') {
575 $sql = "select * from (".$sql.") where rownum <= ?";
576 } else {
577 $sql = "select * from (".$sql.") where rownum <= :adodb_offset";
579 $inputarr['adodb_offset'] = $nrows;
580 $nrows = -1;
582 // note that $nrows = 0 still has to work ==> no rows returned
584 $rs =& ADOConnection::SelectLimit($sql,$nrows,$offset,$inputarr,$secs2cache);
585 return $rs;
587 } else {
588 // Algorithm by Tomas V V Cox, from PEAR DB oci8.php
590 // Let Oracle return the name of the columns
591 $q_fields = "SELECT * FROM (".$sql.") WHERE NULL = NULL";
593 $false = false;
594 if (! $stmt_arr = $this->Prepare($q_fields)) {
595 return $false;
597 $stmt = $stmt_arr[1];
599 if (is_array($inputarr)) {
600 foreach($inputarr as $k => $v) {
601 if (is_array($v)) {
602 if (sizeof($v) == 2) // suggested by g.giunta@libero.
603 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
604 else
605 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
606 } else {
607 $len = -1;
608 if ($v === ' ') $len = 1;
609 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
610 $bindarr[$k] = $v;
611 } else { // dynamic sql, so rebind every time
612 OCIBindByName($stmt,":$k",$inputarr[$k],$len);
618 if (!OCIExecute($stmt, OCI_DEFAULT)) {
619 OCIFreeStatement($stmt);
620 return $false;
623 $ncols = OCINumCols($stmt);
624 for ( $i = 1; $i <= $ncols; $i++ ) {
625 $cols[] = '"'.OCIColumnName($stmt, $i).'"';
627 $result = false;
629 OCIFreeStatement($stmt);
630 $fields = implode(',', $cols);
631 $nrows += $offset;
632 $offset += 1; // in Oracle rownum starts at 1
634 if ($this->databaseType == 'oci8po') {
635 $sql = "SELECT $fields FROM".
636 "(SELECT rownum as adodb_rownum, $fields FROM".
637 " ($sql) WHERE rownum <= ?".
638 ") WHERE adodb_rownum >= ?";
639 } else {
640 $sql = "SELECT $fields FROM".
641 "(SELECT rownum as adodb_rownum, $fields FROM".
642 " ($sql) WHERE rownum <= :adodb_nrows".
643 ") WHERE adodb_rownum >= :adodb_offset";
645 $inputarr['adodb_nrows'] = $nrows;
646 $inputarr['adodb_offset'] = $offset;
648 if ($secs2cache>0) $rs =& $this->CacheExecute($secs2cache, $sql,$inputarr);
649 else $rs =& $this->Execute($sql,$inputarr);
650 return $rs;
656 * Usage:
657 * Store BLOBs and CLOBs
659 * Example: to store $var in a blob
661 * $conn->Execute('insert into TABLE (id,ablob) values(12,empty_blob())');
662 * $conn->UpdateBlob('TABLE', 'ablob', $varHoldingBlob, 'ID=12', 'BLOB');
664 * $blobtype supports 'BLOB' and 'CLOB', but you need to change to 'empty_clob()'.
666 * to get length of LOB:
667 * select DBMS_LOB.GETLENGTH(ablob) from TABLE
669 * If you are using CURSOR_SHARING = force, it appears this will case a segfault
670 * under oracle 8.1.7.0. Run:
671 * $db->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
672 * before UpdateBlob() then...
675 function UpdateBlob($table,$column,$val,$where,$blobtype='BLOB')
678 //if (strlen($val) < 4000) return $this->Execute("UPDATE $table SET $column=:blob WHERE $where",array('blob'=>$val)) != false;
680 switch(strtoupper($blobtype)) {
681 default: ADOConnection::outp("<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
682 case 'BLOB': $type = OCI_B_BLOB; break;
683 case 'CLOB': $type = OCI_B_CLOB; break;
686 if ($this->databaseType == 'oci8po')
687 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
688 else
689 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
691 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
692 $arr['blob'] = array($desc,-1,$type);
693 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=EXACT');
694 $commit = $this->autoCommit;
695 if ($commit) $this->BeginTrans();
696 $rs = $this->_Execute($sql,$arr);
697 if ($rez = !empty($rs)) $desc->save($val);
698 $desc->free();
699 if ($commit) $this->CommitTrans();
700 if ($this->session_sharing_force_blob) $this->Execute('ALTER SESSION SET CURSOR_SHARING=FORCE');
702 if ($rez) $rs->Close();
703 return $rez;
707 * Usage: store file pointed to by $var in a blob
709 function UpdateBlobFile($table,$column,$val,$where,$blobtype='BLOB')
711 switch(strtoupper($blobtype)) {
712 default: ADOConnection::outp( "<b>UpdateBlob</b>: Unknown blobtype=$blobtype"); return false;
713 case 'BLOB': $type = OCI_B_BLOB; break;
714 case 'CLOB': $type = OCI_B_CLOB; break;
717 if ($this->databaseType == 'oci8po')
718 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO ?";
719 else
720 $sql = "UPDATE $table set $column=EMPTY_{$blobtype}() WHERE $where RETURNING $column INTO :blob";
722 $desc = OCINewDescriptor($this->_connectionID, OCI_D_LOB);
723 $arr['blob'] = array($desc,-1,$type);
725 $this->BeginTrans();
726 $rs = ADODB_oci8::Execute($sql,$arr);
727 if ($rez = !empty($rs)) $desc->savefile($val);
728 $desc->free();
729 $this->CommitTrans();
731 if ($rez) $rs->Close();
732 return $rez;
736 * Execute SQL
738 * @param sql SQL statement to execute, or possibly an array holding prepared statement ($sql[0] will hold sql text)
739 * @param [inputarr] holds the input data to bind to. Null elements will be set to null.
740 * @return RecordSet or false
742 function &Execute($sql,$inputarr=false)
744 if ($this->fnExecute) {
745 $fn = $this->fnExecute;
746 $ret =& $fn($this,$sql,$inputarr);
747 if (isset($ret)) return $ret;
749 if ($inputarr) {
750 #if (!is_array($inputarr)) $inputarr = array($inputarr);
752 $element0 = reset($inputarr);
754 # is_object check because oci8 descriptors can be passed in
755 if (is_array($element0) && !is_object(reset($element0))) {
756 if (is_string($sql))
757 $stmt = $this->Prepare($sql);
758 else
759 $stmt = $sql;
761 foreach($inputarr as $arr) {
762 $ret =& $this->_Execute($stmt,$arr);
763 if (!$ret) return $ret;
765 } else {
766 $ret =& $this->_Execute($sql,$inputarr);
769 } else {
770 $ret =& $this->_Execute($sql,false);
773 return $ret;
777 Example of usage:
779 $stmt = $this->Prepare('insert into emp (empno, ename) values (:empno, :ename)');
781 function Prepare($sql,$cursor=false)
783 static $BINDNUM = 0;
785 $stmt = OCIParse($this->_connectionID,$sql);
787 if (!$stmt) {
788 $this->_errorMsg = false;
789 $this->_errorCode = false;
790 $arr = @OCIError($this->_connectionID);
791 if ($arr === false) return false;
793 $this->_errorMsg = $arr['message'];
794 $this->_errorCode = $arr['code'];
795 return false;
798 $BINDNUM += 1;
800 $sttype = @OCIStatementType($stmt);
801 if ($sttype == 'BEGIN' || $sttype == 'DECLARE') {
802 return array($sql,$stmt,0,$BINDNUM, ($cursor) ? OCINewCursor($this->_connectionID) : false);
804 return array($sql,$stmt,0,$BINDNUM);
808 Call an oracle stored procedure and returns a cursor variable as a recordset.
809 Concept by Robert Tuttle robert@ud.com
811 Example:
812 Note: we return a cursor variable in :RS2
813 $rs = $db->ExecuteCursor("BEGIN adodb.open_tab(:RS2); END;",'RS2');
815 $rs = $db->ExecuteCursor(
816 "BEGIN :RS2 = adodb.getdata(:VAR1); END;",
817 'RS2',
818 array('VAR1' => 'Mr Bean'));
821 function &ExecuteCursor($sql,$cursorName='rs',$params=false)
823 if (is_array($sql)) $stmt = $sql;
824 else $stmt = ADODB_oci8::Prepare($sql,true); # true to allocate OCINewCursor
826 if (is_array($stmt) && sizeof($stmt) >= 5) {
827 $hasref = true;
828 $ignoreCur = false;
829 $this->Parameter($stmt, $ignoreCur, $cursorName, false, -1, OCI_B_CURSOR);
830 if ($params) {
831 foreach($params as $k => $v) {
832 $this->Parameter($stmt,$params[$k], $k);
835 } else
836 $hasref = false;
838 $rs =& $this->Execute($stmt);
839 if ($rs) {
840 if ($rs->databaseType == 'array') OCIFreeCursor($stmt[4]);
841 else if ($hasref) $rs->_refcursor = $stmt[4];
843 return $rs;
847 Bind a variable -- very, very fast for executing repeated statements in oracle.
848 Better than using
849 for ($i = 0; $i < $max; $i++) {
850 $p1 = ?; $p2 = ?; $p3 = ?;
851 $this->Execute("insert into table (col0, col1, col2) values (:0, :1, :2)",
852 array($p1,$p2,$p3));
855 Usage:
856 $stmt = $DB->Prepare("insert into table (col0, col1, col2) values (:0, :1, :2)");
857 $DB->Bind($stmt, $p1);
858 $DB->Bind($stmt, $p2);
859 $DB->Bind($stmt, $p3);
860 for ($i = 0; $i < $max; $i++) {
861 $p1 = ?; $p2 = ?; $p3 = ?;
862 $DB->Execute($stmt);
865 Some timings:
866 ** Test table has 3 cols, and 1 index. Test to insert 1000 records
867 Time 0.6081s (1644.60 inserts/sec) with direct OCIParse/OCIExecute
868 Time 0.6341s (1577.16 inserts/sec) with ADOdb Prepare/Bind/Execute
869 Time 1.5533s ( 643.77 inserts/sec) with pure SQL using Execute
871 Now if PHP only had batch/bulk updating like Java or PL/SQL...
873 Note that the order of parameters differs from OCIBindByName,
874 because we default the names to :0, :1, :2
876 function Bind(&$stmt,&$var,$size=4000,$type=false,$name=false,$isOutput=false)
879 if (!is_array($stmt)) return false;
881 if (($type == OCI_B_CURSOR) && sizeof($stmt) >= 5) {
882 return OCIBindByName($stmt[1],":".$name,$stmt[4],$size,$type);
885 if ($name == false) {
886 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size,$type);
887 else $rez = OCIBindByName($stmt[1],":".$stmt[2],$var,$size); // +1 byte for null terminator
888 $stmt[2] += 1;
889 } else if (oci_lob_desc($type)) {
890 if ($this->debug) {
891 ADOConnection::outp("<b>Bind</b>: name = $name");
893 //we have to create a new Descriptor here
894 $numlob = count($this->_refLOBs);
895 $this->_refLOBs[$numlob]['LOB'] = OCINewDescriptor($this->_connectionID, oci_lob_desc($type));
896 $this->_refLOBs[$numlob]['TYPE'] = $isOutput;
898 $tmp = &$this->_refLOBs[$numlob]['LOB'];
899 $rez = OCIBindByName($stmt[1], ":".$name, $tmp, -1, $type);
900 if ($this->debug) {
901 ADOConnection::outp("<b>Bind</b>: descriptor has been allocated, var (".$name.") binded");
904 // if type is input then write data to lob now
905 if ($isOutput == false) {
906 $var = $this->BlobEncode($var);
907 $tmp->WriteTemporary($var);
908 $this->_refLOBs[$numlob]['VAR'] = &$var;
909 if ($this->debug) {
910 ADOConnection::outp("<b>Bind</b>: LOB has been written to temp");
912 } else {
913 $this->_refLOBs[$numlob]['VAR'] = &$var;
915 $rez = $tmp;
916 } else {
917 if ($this->debug)
918 ADOConnection::outp("<b>Bind</b>: name = $name");
920 if ($type !== false) $rez = OCIBindByName($stmt[1],":".$name,$var,$size,$type);
921 else $rez = OCIBindByName($stmt[1],":".$name,$var,$size); // +1 byte for null terminator
924 return $rez;
927 function Param($name,$type=false)
929 return ':'.$name;
933 Usage:
934 $stmt = $db->Prepare('select * from table where id =:myid and group=:group');
935 $db->Parameter($stmt,$id,'myid');
936 $db->Parameter($stmt,$group,'group');
937 $db->Execute($stmt);
939 @param $stmt Statement returned by Prepare() or PrepareSP().
940 @param $var PHP variable to bind to
941 @param $name Name of stored procedure variable name to bind to.
942 @param [$isOutput] Indicates direction of parameter 0/false=IN 1=OUT 2= IN/OUT. This is ignored in oci8.
943 @param [$maxLen] Holds an maximum length of the variable.
944 @param [$type] The data type of $var. Legal values depend on driver.
946 See OCIBindByName documentation at php.net.
948 function Parameter(&$stmt,&$var,$name,$isOutput=false,$maxLen=4000,$type=false)
950 if ($this->debug) {
951 $prefix = ($isOutput) ? 'Out' : 'In';
952 $ztype = (empty($type)) ? 'false' : $type;
953 ADOConnection::outp( "{$prefix}Parameter(\$stmt, \$php_var='$var', \$name='$name', \$maxLen=$maxLen, \$type=$ztype);");
955 return $this->Bind($stmt,$var,$maxLen,$type,$name,$isOutput);
959 returns query ID if successful, otherwise false
960 this version supports:
962 1. $db->execute('select * from table');
964 2. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
965 $db->execute($prepared_statement, array(1,2,3));
967 3. $db->execute('insert into table (a,b,c) values (:a,:b,:c)',array('a'=>1,'b'=>2,'c'=>3));
969 4. $db->prepare('insert into table (a,b,c) values (:0,:1,:2)');
970 $db->bind($stmt,1); $db->bind($stmt,2); $db->bind($stmt,3);
971 $db->execute($stmt);
973 function _query($sql,$inputarr)
975 if (is_array($sql)) { // is prepared sql
976 $stmt = $sql[1];
978 // we try to bind to permanent array, so that OCIBindByName is persistent
979 // and carried out once only - note that max array element size is 4000 chars
980 if (is_array($inputarr)) {
981 $bindpos = $sql[3];
982 if (isset($this->_bind[$bindpos])) {
983 // all tied up already
984 $bindarr = &$this->_bind[$bindpos];
985 } else {
986 // one statement to bind them all
987 $bindarr = array();
988 foreach($inputarr as $k => $v) {
989 $bindarr[$k] = $v;
990 OCIBindByName($stmt,":$k",$bindarr[$k],is_string($v) && strlen($v)>4000 ? -1 : 4000);
992 $this->_bind[$bindpos] = &$bindarr;
995 } else {
996 $stmt=OCIParse($this->_connectionID,$sql);
999 $this->_stmt = $stmt;
1000 if (!$stmt) return false;
1002 if (defined('ADODB_PREFETCH_ROWS')) @OCISetPrefetch($stmt,ADODB_PREFETCH_ROWS);
1004 if (is_array($inputarr)) {
1005 foreach($inputarr as $k => $v) {
1006 if (is_array($v)) {
1007 if (sizeof($v) == 2) // suggested by g.giunta@libero.
1008 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1]);
1009 else
1010 OCIBindByName($stmt,":$k",$inputarr[$k][0],$v[1],$v[2]);
1012 if ($this->debug==99) echo "name=:$k",' var='.$inputarr[$k][0],' len='.$v[1],' type='.$v[2],'<br>';
1013 } else {
1014 $len = -1;
1015 if ($v === ' ') $len = 1;
1016 if (isset($bindarr)) { // is prepared sql, so no need to ocibindbyname again
1017 $bindarr[$k] = $v;
1018 } else { // dynamic sql, so rebind every time
1019 OCIBindByName($stmt,":$k",$inputarr[$k],$len);
1025 $this->_errorMsg = false;
1026 $this->_errorCode = false;
1027 if (OCIExecute($stmt,$this->_commit)) {
1028 //OCIInternalDebug(1);
1029 if (count($this -> _refLOBs) > 0) {
1031 foreach ($this -> _refLOBs as $key => $value) {
1032 if ($this -> _refLOBs[$key]['TYPE'] == true) {
1033 $tmp = $this -> _refLOBs[$key]['LOB'] -> load();
1034 if ($this -> debug) {
1035 ADOConnection::outp("<b>OUT LOB</b>: LOB has been loaded. <br>");
1037 //$_GLOBALS[$this -> _refLOBs[$key]['VAR']] = $tmp;
1038 $this -> _refLOBs[$key]['VAR'] = $tmp;
1039 } else {
1040 $this->_refLOBs[$key]['LOB']->save($this->_refLOBs[$key]['VAR']);
1041 $this -> _refLOBs[$key]['LOB']->free();
1042 unset($this -> _refLOBs[$key]);
1043 if ($this->debug) {
1044 ADOConnection::outp("<b>IN LOB</b>: LOB has been saved. <br>");
1050 switch (@OCIStatementType($stmt)) {
1051 case "SELECT":
1052 return $stmt;
1054 case 'DECLARE':
1055 case "BEGIN":
1056 if (is_array($sql) && !empty($sql[4])) {
1057 $cursor = $sql[4];
1058 if (is_resource($cursor)) {
1059 $ok = OCIExecute($cursor);
1060 return $cursor;
1062 return $stmt;
1063 } else {
1064 if (is_resource($stmt)) {
1065 OCIFreeStatement($stmt);
1066 return true;
1068 return $stmt;
1070 break;
1071 default :
1072 // ociclose -- no because it could be used in a LOB?
1073 return true;
1076 return false;
1079 // returns true or false
1080 function _close()
1082 if (!$this->_connectionID) return;
1084 if (!$this->autoCommit) OCIRollback($this->_connectionID);
1085 if (count($this->_refLOBs) > 0) {
1086 foreach ($this ->_refLOBs as $key => $value) {
1087 $this->_refLOBs[$key]['LOB']->free();
1088 unset($this->_refLOBs[$key]);
1091 OCILogoff($this->_connectionID);
1093 $this->_stmt = false;
1094 $this->_connectionID = false;
1097 function MetaPrimaryKeys($table, $owner=false,$internalKey=false)
1099 if ($internalKey) return array('ROWID');
1101 // tested with oracle 8.1.7
1102 $table = strtoupper($table);
1103 if ($owner) {
1104 $owner_clause = "AND ((a.OWNER = b.OWNER) AND (a.OWNER = UPPER('$owner')))";
1105 $ptab = 'ALL_';
1106 } else {
1107 $owner_clause = '';
1108 $ptab = 'USER_';
1110 $sql = "
1111 SELECT /*+ RULE */ distinct b.column_name
1112 FROM {$ptab}CONSTRAINTS a
1113 , {$ptab}CONS_COLUMNS b
1114 WHERE ( UPPER(b.table_name) = ('$table'))
1115 AND (UPPER(a.table_name) = ('$table') and a.constraint_type = 'P')
1116 $owner_clause
1117 AND (a.constraint_name = b.constraint_name)";
1119 $rs = $this->Execute($sql);
1120 if ($rs && !$rs->EOF) {
1121 $arr =& $rs->GetArray();
1122 $a = array();
1123 foreach($arr as $v) {
1124 $a[] = reset($v);
1126 return $a;
1128 else return false;
1131 // http://gis.mit.edu/classes/11.521/sqlnotes/referential_integrity.html
1132 function MetaForeignKeys($table, $owner=false)
1134 global $ADODB_FETCH_MODE;
1136 $save = $ADODB_FETCH_MODE;
1137 $ADODB_FETCH_MODE = ADODB_FETCH_NUM;
1138 $table = $this->qstr(strtoupper($table));
1139 if (!$owner) {
1140 $owner = $this->user;
1141 $tabp = 'user_';
1142 } else
1143 $tabp = 'all_';
1145 $owner = ' and owner='.$this->qstr(strtoupper($owner));
1147 $sql =
1148 "select constraint_name,r_owner,r_constraint_name
1149 from {$tabp}constraints
1150 where constraint_type = 'R' and table_name = $table $owner";
1152 $constraints =& $this->GetArray($sql);
1153 $arr = false;
1154 foreach($constraints as $constr) {
1155 $cons = $this->qstr($constr[0]);
1156 $rowner = $this->qstr($constr[1]);
1157 $rcons = $this->qstr($constr[2]);
1158 $cols = $this->GetArray("select column_name from {$tabp}cons_columns where constraint_name=$cons $owner order by position");
1159 $tabcol = $this->GetArray("select table_name,column_name from {$tabp}cons_columns where owner=$rowner and constraint_name=$rcons order by position");
1161 if ($cols && $tabcol)
1162 for ($i=0, $max=sizeof($cols); $i < $max; $i++) {
1163 $arr[$tabcol[$i][0]] = $cols[$i][0].'='.$tabcol[$i][1];
1166 $ADODB_FETCH_MODE = $save;
1168 return $arr;
1172 function CharMax()
1174 return 4000;
1177 function TextMax()
1179 return 4000;
1183 * Quotes a string.
1184 * An example is $db->qstr("Don't bother",magic_quotes_runtime());
1186 * @param s the string to quote
1187 * @param [magic_quotes] if $s is GET/POST var, set to get_magic_quotes_gpc().
1188 * This undoes the stupidity of magic quotes for GPC.
1190 * @return quoted string to be sent back to database
1192 function qstr($s,$magic_quotes=false)
1194 //$nofixquotes=false;
1196 if ($this->noNullStrings && strlen($s)==0)$s = ' ';
1197 if (!$magic_quotes) {
1198 if ($this->replaceQuote[0] == '\\'){
1199 $s = str_replace('\\','\\\\',$s);
1201 return "'".str_replace("'",$this->replaceQuote,$s)."'";
1204 // undo magic quotes for "
1205 $s = str_replace('\\"','"',$s);
1207 $s = str_replace('\\\\','\\',$s);
1208 return "'".str_replace("\\'",$this->replaceQuote,$s)."'";
1214 /*--------------------------------------------------------------------------------------
1215 Class Name: Recordset
1216 --------------------------------------------------------------------------------------*/
1218 class ADORecordset_oci8 extends ADORecordSet {
1220 var $databaseType = 'oci8';
1221 var $bind=false;
1222 var $_fieldobjs;
1224 //var $_arr = false;
1226 function ADORecordset_oci8($queryID,$mode=false)
1228 if ($mode === false) {
1229 global $ADODB_FETCH_MODE;
1230 $mode = $ADODB_FETCH_MODE;
1232 switch ($mode)
1234 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1235 case ADODB_FETCH_DEFAULT:
1236 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1237 case ADODB_FETCH_NUM:
1238 default:
1239 $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1242 $this->adodbFetchMode = $mode;
1243 $this->_queryID = $queryID;
1247 function Init()
1249 if ($this->_inited) return;
1251 $this->_inited = true;
1252 if ($this->_queryID) {
1254 $this->_currentRow = 0;
1255 @$this->_initrs();
1256 $this->EOF = !$this->_fetch();
1259 // based on idea by Gaetano Giunta to detect unusual oracle errors
1260 // see http://phplens.com/lens/lensforum/msgs.php?id=6771
1261 $err = OCIError($this->_queryID);
1262 if ($err && $this->connection->debug) ADOConnection::outp($err);
1265 if (!is_array($this->fields)) {
1266 $this->_numOfRows = 0;
1267 $this->fields = array();
1269 } else {
1270 $this->fields = array();
1271 $this->_numOfRows = 0;
1272 $this->_numOfFields = 0;
1273 $this->EOF = true;
1277 function _initrs()
1279 $this->_numOfRows = -1;
1280 $this->_numOfFields = OCInumcols($this->_queryID);
1281 if ($this->_numOfFields>0) {
1282 $this->_fieldobjs = array();
1283 $max = $this->_numOfFields;
1284 for ($i=0;$i<$max; $i++) $this->_fieldobjs[] = $this->_FetchField($i);
1288 /* Returns: an object containing field information.
1289 Get column information in the Recordset object. fetchField() can be used in order to obtain information about
1290 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by
1291 fetchField() is retrieved. */
1293 function &_FetchField($fieldOffset = -1)
1295 $fld = new ADOFieldObject;
1296 $fieldOffset += 1;
1297 $fld->name =OCIcolumnname($this->_queryID, $fieldOffset);
1298 $fld->type = OCIcolumntype($this->_queryID, $fieldOffset);
1299 $fld->max_length = OCIcolumnsize($this->_queryID, $fieldOffset);
1300 if ($fld->type == 'NUMBER') {
1301 $p = OCIColumnPrecision($this->_queryID, $fieldOffset);
1302 $sc = OCIColumnScale($this->_queryID, $fieldOffset);
1303 if ($p != 0 && $sc == 0) $fld->type = 'INT';
1304 //echo " $this->name ($p.$sc) ";
1306 return $fld;
1309 /* For some reason, OCIcolumnname fails when called after _initrs() so we cache it */
1310 function &FetchField($fieldOffset = -1)
1312 return $this->_fieldobjs[$fieldOffset];
1317 // 10% speedup to move MoveNext to child class
1318 function _MoveNext()
1320 //global $ADODB_EXTENSION;if ($ADODB_EXTENSION) return @adodb_movenext($this);
1322 if ($this->EOF) return false;
1324 $this->_currentRow++;
1325 if(@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode))
1326 return true;
1327 $this->EOF = true;
1329 return false;
1330 } */
1333 function MoveNext()
1335 if (@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) {
1336 $this->_currentRow += 1;
1337 return true;
1339 if (!$this->EOF) {
1340 $this->_currentRow += 1;
1341 $this->EOF = true;
1343 return false;
1347 # does not work as first record is retrieved in _initrs(), so is not included in GetArray()
1348 function &GetArray($nRows = -1)
1350 global $ADODB_OCI8_GETARRAY;
1352 if (true || !empty($ADODB_OCI8_GETARRAY)) {
1353 # does not support $ADODB_ANSI_PADDING_OFF
1355 //OCI_RETURN_NULLS and OCI_RETURN_LOBS is set by OCIfetchstatement
1356 switch($this->adodbFetchMode) {
1357 case ADODB_FETCH_NUM:
1359 $ncols = @OCIfetchstatement($this->_queryID, $results, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW+OCI_NUM);
1360 $results = array_merge(array($this->fields),$results);
1361 return $results;
1363 case ADODB_FETCH_ASSOC:
1364 if (ADODB_ASSOC_CASE != 2 || $this->databaseType != 'oci8') break;
1366 $ncols = @OCIfetchstatement($this->_queryID, $assoc, 0, $nRows, OCI_FETCHSTATEMENT_BY_ROW);
1367 $results =& array_merge(array($this->fields),$assoc);
1368 return $results;
1370 default:
1371 break;
1375 $results =& ADORecordSet::GetArray($nRows);
1376 return $results;
1378 } */
1380 /* Optimize SelectLimit() by using OCIFetch() instead of OCIFetchInto() */
1381 function &GetArrayLimit($nrows,$offset=-1)
1383 if ($offset <= 0) {
1384 $arr =& $this->GetArray($nrows);
1385 return $arr;
1387 $arr = array();
1388 for ($i=1; $i < $offset; $i++)
1389 if (!@OCIFetch($this->_queryID)) return $arr;
1391 if (!@OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode)) return $arr;;
1392 $results = array();
1393 $cnt = 0;
1394 while (!$this->EOF && $nrows != $cnt) {
1395 $results[$cnt++] = $this->fields;
1396 $this->MoveNext();
1399 return $results;
1403 /* Use associative array to get fields array */
1404 function Fields($colname)
1406 if (!$this->bind) {
1407 $this->bind = array();
1408 for ($i=0; $i < $this->_numOfFields; $i++) {
1409 $o = $this->FetchField($i);
1410 $this->bind[strtoupper($o->name)] = $i;
1414 return $this->fields[$this->bind[strtoupper($colname)]];
1419 function _seek($row)
1421 return false;
1424 function _fetch()
1426 return @OCIfetchinto($this->_queryID,$this->fields,$this->fetchMode);
1429 /* close() only needs to be called if you are worried about using too much memory while your script
1430 is running. All associated result memory for the specified result identifier will automatically be freed. */
1432 function _close()
1434 if ($this->connection->_stmt === $this->_queryID) $this->connection->_stmt = false;
1435 if (!empty($this->_refcursor)) {
1436 OCIFreeCursor($this->_refcursor);
1437 $this->_refcursor = false;
1439 @OCIFreeStatement($this->_queryID);
1440 $this->_queryID = false;
1444 function MetaType($t,$len=-1)
1446 if (is_object($t)) {
1447 $fieldobj = $t;
1448 $t = $fieldobj->type;
1449 $len = $fieldobj->max_length;
1451 switch (strtoupper($t)) {
1452 case 'VARCHAR':
1453 case 'VARCHAR2':
1454 case 'CHAR':
1455 case 'VARBINARY':
1456 case 'BINARY':
1457 case 'NCHAR':
1458 case 'NVARCHAR':
1459 case 'NVARCHAR2':
1460 if (isset($this) && $len <= $this->blobSize) return 'C';
1462 case 'NCLOB':
1463 case 'LONG':
1464 case 'LONG VARCHAR':
1465 case 'CLOB':
1466 return 'X';
1468 case 'LONG RAW':
1469 case 'LONG VARBINARY':
1470 case 'BLOB':
1471 return 'B';
1473 case 'DATE':
1474 return ($this->connection->datetime) ? 'T' : 'D';
1477 case 'TIMESTAMP': return 'T';
1479 case 'INT':
1480 case 'SMALLINT':
1481 case 'INTEGER':
1482 return 'I';
1484 default: return 'N';
1489 class ADORecordSet_ext_oci8 extends ADORecordSet_oci8 {
1490 function ADORecordSet_ext_oci8($queryID,$mode=false)
1492 if ($mode === false) {
1493 global $ADODB_FETCH_MODE;
1494 $mode = $ADODB_FETCH_MODE;
1496 switch ($mode)
1498 case ADODB_FETCH_ASSOC:$this->fetchMode = OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1499 case ADODB_FETCH_DEFAULT:
1500 case ADODB_FETCH_BOTH:$this->fetchMode = OCI_NUM+OCI_ASSOC+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1501 case ADODB_FETCH_NUM:
1502 default: $this->fetchMode = OCI_NUM+OCI_RETURN_NULLS+OCI_RETURN_LOBS; break;
1504 $this->adodbFetchMode = $mode;
1505 $this->_queryID = $queryID;
1508 function MoveNext()
1510 return adodb_movenext($this);