1<?php 2/* 3V4.65 22 July 2005 (c) 2000-2005 John Lim (jlim@natsoft.com.my). All rights reserved. 4 Released under both BSD license and Lesser GPL library license. 5 Whenever there is any discrepancy between the two licenses, 6 the BSD license will take precedence. 7 8 Latest version is available at http://adodb.sourceforge.net 9 10 Oracle data driver. Requires Oracle client. Works on Windows and Unix and Oracle 7. 11 12 If you are using Oracle 8 or later, use the oci8 driver which is much better and more reliable. 13*/ 14 15// security - hide paths 16if (!defined('ADODB_DIR')) die(); 17 18class ADODB_oracle extends ADOConnection { 19 var $databaseType = "oracle"; 20 var $replaceQuote = "''"; // string to use to replace quotes 21 var $concat_operator='||'; 22 var $_curs; 23 var $_initdate = true; // init date to YYYY-MM-DD 24 var $metaTablesSQL = 'select table_name from cat'; 25 var $metaColumnsSQL = "select cname,coltype,width from col where tname='%s' order by colno"; 26 var $sysDate = "TO_DATE(TO_CHAR(SYSDATE,'YYYY-MM-DD'),'YYYY-MM-DD')"; 27 var $sysTimeStamp = 'SYSDATE'; 28 var $connectSID = true; 29 30 function ADODB_oracle() 31 { 32 } 33 34 // format and return date string in database date format 35 function DBDate($d) 36 { 37 if (is_string($d)) $d = ADORecordSet::UnixDate($d); 38 return 'TO_DATE('.adodb_date($this->fmtDate,$d).",'YYYY-MM-DD')"; 39 } 40 41 // format and return date string in database timestamp format 42 function DBTimeStamp($ts) 43 { 44 45 if (is_string($ts)) $d = ADORecordSet::UnixTimeStamp($ts); 46 return 'TO_DATE('.adodb_date($this->fmtTimeStamp,$ts).",'RRRR-MM-DD, HH:MI:SS AM')"; 47 } 48 49 50 function BeginTrans() 51 { 52 $this->autoCommit = false; 53 ora_commitoff($this->_connectionID); 54 return true; 55 } 56 57 58 function CommitTrans($ok=true) 59 { 60 if (!$ok) return $this->RollbackTrans(); 61 $ret = ora_commit($this->_connectionID); 62 ora_commiton($this->_connectionID); 63 return $ret; 64 } 65 66 67 function RollbackTrans() 68 { 69 $ret = ora_rollback($this->_connectionID); 70 ora_commiton($this->_connectionID); 71 return $ret; 72 } 73 74 75 /* there seems to be a bug in the oracle extension -- always returns ORA-00000 - no error */ 76 function ErrorMsg() 77 { 78 if ($this->_errorMsg !== false) return $this->_errorMsg; 79 80 if (is_resource($this->_curs)) $this->_errorMsg = @ora_error($this->_curs); 81 if (empty($this->_errorMsg)) $this->_errorMsg = @ora_error($this->_connectionID); 82 return $this->_errorMsg; 83 } 84 85 86 function ErrorNo() 87 { 88 if ($this->_errorCode !== false) return $this->_errorCode; 89 90 if (is_resource($this->_curs)) $this->_errorCode = @ora_errorcode($this->_curs); 91 if (empty($this->_errorCode)) $this->_errorCode = @ora_errorcode($this->_connectionID); 92 return $this->_errorCode; 93 } 94 95 96 97 // returns true or false 98 function _connect($argHostname, $argUsername, $argPassword, $argDatabasename, $mode=0) 99 { 100 if (!function_exists('ora_plogon')) return null; 101 102 // <G. Giunta 2003/03/03/> Reset error messages before connecting 103 $this->_errorMsg = false; 104 $this->_errorCode = false; 105 106 // G. Giunta 2003/08/13 - This looks danegrously suspicious: why should we want to set 107 // the oracle home to the host name of remote DB? 108// if ($argHostname) putenv("ORACLE_HOME=$argHostname"); 109 110 if($argHostname) { // code copied from version submitted for oci8 by Jorma Tuomainen <jorma.tuomainen@ppoy.fi> 111 if (empty($argDatabasename)) $argDatabasename = $argHostname; 112 else { 113 if(strpos($argHostname,":")) { 114 $argHostinfo=explode(":",$argHostname); 115 $argHostname=$argHostinfo[0]; 116 $argHostport=$argHostinfo[1]; 117 } else { 118 $argHostport="1521"; 119 } 120 121 122 if ($this->connectSID) { 123 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname 124 .")(PORT=$argHostport))(CONNECT_DATA=(SID=$argDatabasename)))"; 125 } else 126 $argDatabasename="(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=".$argHostname 127 .")(PORT=$argHostport))(CONNECT_DATA=(SERVICE_NAME=$argDatabasename)))"; 128 } 129 130 } 131 132 if ($argDatabasename) $argUsername .= "@$argDatabasename"; 133 134 //if ($argHostname) print "<p>Connect: 1st argument should be left blank for $this->databaseType</p>"; 135 if ($mode = 1) 136 $this->_connectionID = ora_plogon($argUsername,$argPassword); 137 else 138 $this->_connectionID = ora_logon($argUsername,$argPassword); 139 if ($this->_connectionID === false) return false; 140 if ($this->autoCommit) ora_commiton($this->_connectionID); 141 if ($this->_initdate) { 142 $rs = $this->_query("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD'"); 143 if ($rs) ora_close($rs); 144 } 145 146 return true; 147 } 148 149 150 // returns true or false 151 function _pconnect($argHostname, $argUsername, $argPassword, $argDatabasename) 152 { 153 return $this->_connect($argHostname, $argUsername, $argPassword, $argDatabasename, 1); 154 } 155 156 157 // returns query ID if successful, otherwise false 158 function _query($sql,$inputarr=false) 159 { 160 // <G. Giunta 2003/03/03/> Reset error messages before executing 161 $this->_errorMsg = false; 162 $this->_errorCode = false; 163 164 $curs = ora_open($this->_connectionID); 165 166 if ($curs === false) return false; 167 $this->_curs = $curs; 168 if (!ora_parse($curs,$sql)) return false; 169 if (ora_exec($curs)) return $curs; 170 // <G. Giunta 2004/03/03> before we close the cursor, we have to store the error message 171 // that we can obtain ONLY from the cursor (and not from the connection) 172 $this->_errorCode = @ora_errorcode($curs); 173 $this->_errorMsg = @ora_error($curs); 174 // </G. Giunta 2004/03/03> 175 @ora_close($curs); 176 return false; 177 } 178 179 180 // returns true or false 181 function _close() 182 { 183 return @ora_logoff($this->_connectionID); 184 } 185 186 187 188} 189 190 191/*-------------------------------------------------------------------------------------- 192 Class Name: Recordset 193--------------------------------------------------------------------------------------*/ 194 195class ADORecordset_oracle extends ADORecordSet { 196 197 var $databaseType = "oracle"; 198 var $bind = false; 199 200 function ADORecordset_oracle($queryID,$mode=false) 201 { 202 203 if ($mode === false) { 204 global $ADODB_FETCH_MODE; 205 $mode = $ADODB_FETCH_MODE; 206 } 207 $this->fetchMode = $mode; 208 209 $this->_queryID = $queryID; 210 211 $this->_inited = true; 212 $this->fields = array(); 213 if ($queryID) { 214 $this->_currentRow = 0; 215 $this->EOF = !$this->_fetch(); 216 @$this->_initrs(); 217 } else { 218 $this->_numOfRows = 0; 219 $this->_numOfFields = 0; 220 $this->EOF = true; 221 } 222 223 return $this->_queryID; 224 } 225 226 227 228 /* Returns: an object containing field information. 229 Get column information in the Recordset object. fetchField() can be used in order to obtain information about 230 fields in a certain query result. If the field offset isn't specified, the next field that wasn't yet retrieved by 231 fetchField() is retrieved. */ 232 233 function &FetchField($fieldOffset = -1) 234 { 235 $fld = new ADOFieldObject; 236 $fld->name = ora_columnname($this->_queryID, $fieldOffset); 237 $fld->type = ora_columntype($this->_queryID, $fieldOffset); 238 $fld->max_length = ora_columnsize($this->_queryID, $fieldOffset); 239 return $fld; 240 } 241 242 /* Use associative array to get fields array */ 243 function Fields($colname) 244 { 245 if (!$this->bind) { 246 $this->bind = array(); 247 for ($i=0; $i < $this->_numOfFields; $i++) { 248 $o = $this->FetchField($i); 249 $this->bind[strtoupper($o->name)] = $i; 250 } 251 } 252 253 return $this->fields[$this->bind[strtoupper($colname)]]; 254 } 255 256 function _initrs() 257 { 258 $this->_numOfRows = -1; 259 $this->_numOfFields = @ora_numcols($this->_queryID); 260 } 261 262 263 function _seek($row) 264 { 265 return false; 266 } 267 268 function _fetch($ignore_fields=false) { 269// should remove call by reference, but ora_fetch_into requires it in 4.0.3pl1 270 if ($this->fetchMode & ADODB_FETCH_ASSOC) 271 return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS|ORA_FETCHINTO_ASSOC); 272 else 273 return @ora_fetch_into($this->_queryID,&$this->fields,ORA_FETCHINTO_NULLS); 274 } 275 276 /* close() only needs to be called if you are worried about using too much memory while your script 277 is running. All associated result memory for the specified result identifier will automatically be freed. */ 278 279 function _close() 280{ 281 return @ora_close($this->_queryID); 282 } 283 284 function MetaType($t,$len=-1) 285 { 286 if (is_object($t)) { 287 $fieldobj = $t; 288 $t = $fieldobj->type; 289 $len = $fieldobj->max_length; 290 } 291 292 switch (strtoupper($t)) { 293 case 'VARCHAR': 294 case 'VARCHAR2': 295 case 'CHAR': 296 case 'VARBINARY': 297 case 'BINARY': 298 if ($len <= $this->blobSize) return 'C'; 299 case 'LONG': 300 case 'LONG VARCHAR': 301 case 'CLOB': 302 return 'X'; 303 case 'LONG RAW': 304 case 'LONG VARBINARY': 305 case 'BLOB': 306 return 'B'; 307 308 case 'DATE': return 'D'; 309 310 //case 'T': return 'T'; 311 312 case 'BIT': return 'L'; 313 case 'INT': 314 case 'SMALLINT': 315 case 'INTEGER': return 'I'; 316 default: return 'N'; 317 } 318 } 319} 320?>