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