adodb-oci8.inc.php 46 KB

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