adodb-lib.inc.php 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262
  1. <?php
  2. // security - hide paths
  3. if (!defined('ADODB_DIR')) die();
  4. global $ADODB_INCLUDED_LIB;
  5. $ADODB_INCLUDED_LIB = 1;
  6. /*
  7. @version v5.20.17 31-Mar-2020
  8. @copyright (c) 2000-2013 John Lim (jlim#natsoft.com). All rights reserved.
  9. @copyright (c) 2014 Damien Regad, Mark Newnham and the ADOdb community
  10. Released under both BSD license and Lesser GPL library license.
  11. Whenever there is any discrepancy between the two licenses,
  12. the BSD license will take precedence. See License.txt.
  13. Set tabs to 4 for best viewing.
  14. Less commonly used functions are placed here to reduce size of adodb.inc.php.
  15. */
  16. function adodb_strip_order_by($sql)
  17. {
  18. $rez = preg_match('/(\sORDER\s+BY\s(?:[^)](?!LIMIT))*)/is', $sql, $arr);
  19. if ($arr)
  20. if (strpos($arr[1], '(') !== false) {
  21. $at = strpos($sql, $arr[1]);
  22. $cntin = 0;
  23. for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
  24. $ch = $sql[$i];
  25. if ($ch == '(') {
  26. $cntin += 1;
  27. } elseif($ch == ')') {
  28. $cntin -= 1;
  29. if ($cntin < 0) {
  30. break;
  31. }
  32. }
  33. }
  34. $sql = substr($sql,0,$at).substr($sql,$i);
  35. } else {
  36. $sql = str_replace($arr[1], '', $sql);
  37. }
  38. return $sql;
  39. }
  40. if (false) {
  41. $sql = 'select * from (select a from b order by a(b),b(c) desc)';
  42. $sql = '(select * from abc order by 1)';
  43. die(adodb_strip_order_by($sql));
  44. }
  45. function adodb_probetypes(&$array,&$types,$probe=8)
  46. {
  47. // probe and guess the type
  48. $types = array();
  49. if ($probe > sizeof($array)) $max = sizeof($array);
  50. else $max = $probe;
  51. for ($j=0;$j < $max; $j++) {
  52. $row = $array[$j];
  53. if (!$row) break;
  54. $i = -1;
  55. foreach($row as $v) {
  56. $i += 1;
  57. if (isset($types[$i]) && $types[$i]=='C') continue;
  58. //print " ($i ".$types[$i]. "$v) ";
  59. $v = trim($v);
  60. if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) {
  61. $types[$i] = 'C'; // once C, always C
  62. continue;
  63. }
  64. if ($j == 0) {
  65. // If empty string, we presume is character
  66. // test for integer for 1st row only
  67. // after that it is up to testing other rows to prove
  68. // that it is not an integer
  69. if (strlen($v) == 0) $types[$i] = 'C';
  70. if (strpos($v,'.') !== false) $types[$i] = 'N';
  71. else $types[$i] = 'I';
  72. continue;
  73. }
  74. if (strpos($v,'.') !== false) $types[$i] = 'N';
  75. }
  76. }
  77. }
  78. function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
  79. {
  80. $oldX = sizeof(reset($arr));
  81. $oldY = sizeof($arr);
  82. if ($hdr) {
  83. $startx = 1;
  84. $hdr = array('Fields');
  85. for ($y = 0; $y < $oldY; $y++) {
  86. $hdr[] = $arr[$y][0];
  87. }
  88. } else
  89. $startx = 0;
  90. for ($x = $startx; $x < $oldX; $x++) {
  91. if ($fobjs) {
  92. $o = $fobjs[$x];
  93. $newarr[] = array($o->name);
  94. } else
  95. $newarr[] = array();
  96. for ($y = 0; $y < $oldY; $y++) {
  97. $newarr[$x-$startx][] = $arr[$y][$x];
  98. }
  99. }
  100. }
  101. // Force key to upper.
  102. // See also http://www.php.net/manual/en/function.array-change-key-case.php
  103. function _array_change_key_case($an_array)
  104. {
  105. if (is_array($an_array)) {
  106. $new_array = array();
  107. foreach($an_array as $key=>$value)
  108. $new_array[strtoupper($key)] = $value;
  109. return $new_array;
  110. }
  111. return $an_array;
  112. }
  113. function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
  114. {
  115. if (count($fieldArray) == 0) return 0;
  116. $first = true;
  117. $uSet = '';
  118. if (!is_array($keyCol)) {
  119. $keyCol = array($keyCol);
  120. }
  121. foreach($fieldArray as $k => $v) {
  122. if ($v === null) {
  123. $v = 'NULL';
  124. $fieldArray[$k] = $v;
  125. } else if ($autoQuote && /*!is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ strcasecmp($v,$zthis->null2null)!=0) {
  126. $v = $zthis->qstr($v);
  127. $fieldArray[$k] = $v;
  128. }
  129. if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
  130. if ($first) {
  131. $first = false;
  132. $uSet = "$k=$v";
  133. } else
  134. $uSet .= ",$k=$v";
  135. }
  136. $where = false;
  137. foreach ($keyCol as $v) {
  138. if (isset($fieldArray[$v])) {
  139. if ($where) $where .= ' and '.$v.'='.$fieldArray[$v];
  140. else $where = $v.'='.$fieldArray[$v];
  141. }
  142. }
  143. if ($uSet && $where) {
  144. $update = "UPDATE $table SET $uSet WHERE $where";
  145. $rs = $zthis->Execute($update);
  146. if ($rs) {
  147. if ($zthis->poorAffectedRows) {
  148. /*
  149. The Select count(*) wipes out any errors that the update would have returned.
  150. http://phplens.com/lens/lensforum/msgs.php?id=5696
  151. */
  152. if ($zthis->ErrorNo()<>0) return 0;
  153. # affected_rows == 0 if update field values identical to old values
  154. # for mysql - which is silly.
  155. $cnt = $zthis->GetOne("select count(*) from $table where $where");
  156. if ($cnt > 0) return 1; // record already exists
  157. } else {
  158. if (($zthis->Affected_Rows()>0)) return 1;
  159. }
  160. } else
  161. return 0;
  162. }
  163. // print "<p>Error=".$this->ErrorNo().'<p>';
  164. $first = true;
  165. foreach($fieldArray as $k => $v) {
  166. if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
  167. if ($first) {
  168. $first = false;
  169. $iCols = "$k";
  170. $iVals = "$v";
  171. } else {
  172. $iCols .= ",$k";
  173. $iVals .= ",$v";
  174. }
  175. }
  176. $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
  177. $rs = $zthis->Execute($insert);
  178. return ($rs) ? 2 : 0;
  179. }
  180. function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
  181. $size=0, $selectAttr='',$compareFields0=true)
  182. {
  183. global $ADODB_FETCH_MODE;
  184. $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr);
  185. $hasvalue = $zthis->FieldCount() > 1;
  186. if (!$hasvalue) {
  187. $compareFields0 = true;
  188. }
  189. $value = '';
  190. while(!$zthis->EOF) {
  191. $zval = rtrim(reset($zthis->fields));
  192. if ($blank1stItem && $zval == "") {
  193. $zthis->MoveNext();
  194. continue;
  195. }
  196. if ($hasvalue) {
  197. if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) {
  198. // Get 2nd field's value regardless of its name
  199. $zval2 = current(array_slice($zthis->fields, 1, 1));
  200. } else {
  201. // With NUM or BOTH fetch modes, we have a numeric index
  202. $zval2 = $zthis->fields[1];
  203. }
  204. $zval2 = trim($zval2);
  205. $value = 'value="' . htmlspecialchars($zval2) . '"';
  206. }
  207. $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
  208. $zthis->MoveNext();
  209. } // while
  210. return $s ."\n</select>\n";
  211. }
  212. function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
  213. $size=0, $selectAttr='',$compareFields0=true)
  214. {
  215. global $ADODB_FETCH_MODE;
  216. $s = _adodb_getmenu_select($name, $defstr, $blank1stItem, $multiple, $size, $selectAttr);
  217. $hasvalue = $zthis->FieldCount() > 1;
  218. $hasgroup = $zthis->FieldCount() > 2;
  219. if (!$hasvalue) {
  220. $compareFields0 = true;
  221. }
  222. $value = '';
  223. $optgroup = null;
  224. $firstgroup = true;
  225. while(!$zthis->EOF) {
  226. $zval = rtrim(reset($zthis->fields));
  227. $group = '';
  228. if ($blank1stItem && $zval=="") {
  229. $zthis->MoveNext();
  230. continue;
  231. }
  232. if ($hasvalue) {
  233. if ($ADODB_FETCH_MODE == ADODB_FETCH_ASSOC) {
  234. // Get 2nd field's value regardless of its name
  235. $fields = array_slice($zthis->fields, 1);
  236. $zval2 = current($fields);
  237. if ($hasgroup) {
  238. $group = trim(next($fields));
  239. }
  240. } else {
  241. // With NUM or BOTH fetch modes, we have a numeric index
  242. $zval2 = $zthis->fields[1];
  243. if ($hasgroup) {
  244. $group = trim($zthis->fields[2]);
  245. }
  246. }
  247. $zval2 = trim($zval2);
  248. $value = "value='".htmlspecialchars($zval2)."'";
  249. }
  250. if ($optgroup != $group) {
  251. $optgroup = $group;
  252. if ($firstgroup) {
  253. $firstgroup = false;
  254. } else {
  255. $s .="\n</optgroup>";
  256. }
  257. $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
  258. }
  259. $s .= _adodb_getmenu_option($defstr, $compareFields0 ? $zval : $zval2, $value, $zval);
  260. $zthis->MoveNext();
  261. } // while
  262. // closing last optgroup
  263. if($optgroup != null) {
  264. $s .= "\n</optgroup>";
  265. }
  266. return $s ."\n</select>\n";
  267. }
  268. /**
  269. * Generate the opening SELECT tag for getmenu functions.
  270. *
  271. * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp().
  272. *
  273. * @param string $name
  274. * @param string $defstr
  275. * @param bool $blank1stItem
  276. * @param bool $multiple
  277. * @param int $size
  278. * @param string $selectAttr
  279. *
  280. * @return string HTML
  281. */
  282. function _adodb_getmenu_select($name, $defstr = '', $blank1stItem = true,
  283. $multiple = false, $size = 0, $selectAttr = '')
  284. {
  285. if ($multiple || is_array($defstr)) {
  286. if ($size == 0 ) {
  287. $size = 5;
  288. }
  289. $attr = ' multiple size="' . $size . '"';
  290. if (!strpos($name,'[]')) {
  291. $name .= '[]';
  292. }
  293. } elseif ($size) {
  294. $attr = ' size="' . $size . '"';
  295. } else {
  296. $attr = '';
  297. }
  298. $html = '<select name="' . $name . '"' . $attr . ' ' . $selectAttr . '>';
  299. if ($blank1stItem) {
  300. if (is_string($blank1stItem)) {
  301. $barr = explode(':',$blank1stItem);
  302. if (sizeof($barr) == 1) {
  303. $barr[] = '';
  304. }
  305. $html .= "\n<option value=\"" . $barr[0] . "\">" . $barr[1] . "</option>";
  306. } else {
  307. $html .= "\n<option></option>";
  308. }
  309. }
  310. return $html;
  311. }
  312. /**
  313. * Print the OPTION tags for getmenu functions.
  314. *
  315. * ADOdb internal function, used by _adodb_getmenu() and _adodb_getmenu_gp().
  316. *
  317. * @param string $defstr Default values
  318. * @param string $compare Value to compare against defaults
  319. * @param string $value Ready-to-print `value="xxx"` (or empty) string
  320. * @param string $display Display value
  321. *
  322. * @return string HTML
  323. */
  324. function _adodb_getmenu_option($defstr, $compare, $value, $display)
  325. {
  326. if ( is_array($defstr) && in_array($compare, $defstr)
  327. || !is_array($defstr) && strcasecmp($compare, $defstr) == 0
  328. ) {
  329. $selected = ' selected="selected"';
  330. } else {
  331. $selected = '';
  332. }
  333. return "\n<option $value$selected>" . htmlspecialchars($display) . '</option>';
  334. }
  335. /*
  336. Count the number of records this sql statement will return by using
  337. query rewriting heuristics...
  338. Does not work with UNIONs, except with postgresql and oracle.
  339. Usage:
  340. $conn->Connect(...);
  341. $cnt = _adodb_getcount($conn, $sql);
  342. */
  343. function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
  344. {
  345. $qryRecs = 0;
  346. if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) ||
  347. preg_match('/\s+GROUP\s+BY\s+/is',$sql) ||
  348. preg_match('/\s+UNION\s+/is',$sql)) {
  349. $rewritesql = adodb_strip_order_by($sql);
  350. // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
  351. // but this is only supported by oracle and postgresql...
  352. if ($zthis->dataProvider == 'oci8') {
  353. // Allow Oracle hints to be used for query optimization, Chris Wrye
  354. if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
  355. $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")";
  356. } else
  357. $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")";
  358. } else if (strncmp($zthis->databaseType,'postgres',8) == 0
  359. || strncmp($zthis->databaseType,'mysql',5) == 0
  360. || strncmp($zthis->databaseType,'mssql',5) == 0
  361. || strncmp($zthis->dsnType,'sqlsrv',5) == 0
  362. || strncmp($zthis->dsnType,'mssql',5) == 0
  363. ){
  364. $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
  365. } else {
  366. $rewritesql = "SELECT COUNT(*) FROM ($rewritesql)";
  367. }
  368. } else {
  369. // now replace SELECT ... FROM with SELECT COUNT(*) FROM
  370. if ( strpos($sql, '_ADODB_COUNT') !== FALSE ) {
  371. $rewritesql = preg_replace('/^\s*?SELECT\s+_ADODB_COUNT(.*)_ADODB_COUNT\s/is','SELECT COUNT(*) ',$sql);
  372. } else {
  373. $rewritesql = preg_replace('/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
  374. }
  375. // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
  376. // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
  377. // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
  378. $rewritesql = adodb_strip_order_by($rewritesql);
  379. }
  380. if (isset($rewritesql) && $rewritesql != $sql) {
  381. if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
  382. if ($secs2cache) {
  383. // we only use half the time of secs2cache because the count can quickly
  384. // become inaccurate if new records are added
  385. $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
  386. } else {
  387. $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
  388. }
  389. if ($qryRecs !== false) return $qryRecs;
  390. }
  391. //--------------------------------------------
  392. // query rewrite failed - so try slower way...
  393. // strip off unneeded ORDER BY if no UNION
  394. if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
  395. else $rewritesql = $rewritesql = adodb_strip_order_by($sql);
  396. if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
  397. if ($secs2cache) {
  398. $rstest = $zthis->CacheExecute($secs2cache,$rewritesql,$inputarr);
  399. if (!$rstest) $rstest = $zthis->CacheExecute($secs2cache,$sql,$inputarr);
  400. } else {
  401. $rstest = $zthis->Execute($rewritesql,$inputarr);
  402. if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
  403. }
  404. if ($rstest) {
  405. $qryRecs = $rstest->RecordCount();
  406. if ($qryRecs == -1) {
  407. global $ADODB_EXTENSION;
  408. // some databases will return -1 on MoveLast() - change to MoveNext()
  409. if ($ADODB_EXTENSION) {
  410. while(!$rstest->EOF) {
  411. adodb_movenext($rstest);
  412. }
  413. } else {
  414. while(!$rstest->EOF) {
  415. $rstest->MoveNext();
  416. }
  417. }
  418. $qryRecs = $rstest->_currentRow;
  419. }
  420. $rstest->Close();
  421. if ($qryRecs == -1) return 0;
  422. }
  423. return $qryRecs;
  424. }
  425. /*
  426. Code originally from "Cornel G" <conyg@fx.ro>
  427. This code might not work with SQL that has UNION in it
  428. Also if you are using CachePageExecute(), there is a strong possibility that
  429. data will get out of synch. use CachePageExecute() only with tables that
  430. rarely change.
  431. */
  432. function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
  433. $inputarr=false, $secs2cache=0)
  434. {
  435. $atfirstpage = false;
  436. $atlastpage = false;
  437. $lastpageno=1;
  438. // If an invalid nrows is supplied,
  439. // we assume a default value of 10 rows per page
  440. if (!isset($nrows) || $nrows <= 0) $nrows = 10;
  441. $qryRecs = false; //count records for no offset
  442. $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
  443. $lastpageno = (int) ceil($qryRecs / $nrows);
  444. $zthis->_maxRecordCount = $qryRecs;
  445. // ***** Here we check whether $page is the last page or
  446. // whether we are trying to retrieve
  447. // a page number greater than the last page number.
  448. if ($page >= $lastpageno) {
  449. $page = $lastpageno;
  450. $atlastpage = true;
  451. }
  452. // If page number <= 1, then we are at the first page
  453. if (empty($page) || $page <= 1) {
  454. $page = 1;
  455. $atfirstpage = true;
  456. }
  457. // We get the data we want
  458. $offset = $nrows * ($page-1);
  459. if ($secs2cache > 0)
  460. $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
  461. else
  462. $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
  463. // Before returning the RecordSet, we set the pagination properties we need
  464. if ($rsreturn) {
  465. $rsreturn->_maxRecordCount = $qryRecs;
  466. $rsreturn->rowsPerPage = $nrows;
  467. $rsreturn->AbsolutePage($page);
  468. $rsreturn->AtFirstPage($atfirstpage);
  469. $rsreturn->AtLastPage($atlastpage);
  470. $rsreturn->LastPageNo($lastpageno);
  471. }
  472. return $rsreturn;
  473. }
  474. // Iván Oliva version
  475. function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
  476. {
  477. $atfirstpage = false;
  478. $atlastpage = false;
  479. if (!isset($page) || $page <= 1) {
  480. // If page number <= 1, then we are at the first page
  481. $page = 1;
  482. $atfirstpage = true;
  483. }
  484. if ($nrows <= 0) {
  485. // If an invalid nrows is supplied, we assume a default value of 10 rows per page
  486. $nrows = 10;
  487. }
  488. $pagecounteroffset = ($page * $nrows) - $nrows;
  489. // To find out if there are more pages of rows, simply increase the limit or
  490. // nrows by 1 and see if that number of records was returned. If it was,
  491. // then we know there is at least one more page left, otherwise we are on
  492. // the last page. Therefore allow non-Count() paging with single queries
  493. // rather than three queries as was done before.
  494. $test_nrows = $nrows + 1;
  495. if ($secs2cache > 0) {
  496. $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
  497. } else {
  498. $rsreturn = $zthis->SelectLimit($sql, $test_nrows, $pagecounteroffset, $inputarr, $secs2cache);
  499. }
  500. // Now check to see if the number of rows returned was the higher value we asked for or not.
  501. if ( $rsreturn->_numOfRows == $test_nrows ) {
  502. // Still at least 1 more row, so we are not on last page yet...
  503. // Remove the last row from the RS.
  504. $rsreturn->_numOfRows = ( $rsreturn->_numOfRows - 1 );
  505. } elseif ( $rsreturn->_numOfRows == 0 && $page > 1 ) {
  506. // Likely requested a page that doesn't exist, so need to find the last
  507. // page and return it. Revert to original method and loop through pages
  508. // until we find some data...
  509. $pagecounter = $page + 1;
  510. $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
  511. $rstest = $rsreturn;
  512. if ($rstest) {
  513. while ($rstest && $rstest->EOF && $pagecounter > 0) {
  514. $atlastpage = true;
  515. $pagecounter--;
  516. $pagecounteroffset = $nrows * ($pagecounter - 1);
  517. $rstest->Close();
  518. if ($secs2cache>0) {
  519. $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
  520. }
  521. else {
  522. $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
  523. }
  524. }
  525. if ($rstest) $rstest->Close();
  526. }
  527. if ($atlastpage) {
  528. // If we are at the last page or beyond it, we are going to retrieve it
  529. $page = $pagecounter;
  530. if ($page == 1) {
  531. // We have to do this again in case the last page is the same as
  532. // the first page, that is, the recordset has only 1 page.
  533. $atfirstpage = true;
  534. }
  535. }
  536. // We get the data we want
  537. $offset = $nrows * ($page-1);
  538. if ($secs2cache > 0) {
  539. $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
  540. }
  541. else {
  542. $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
  543. }
  544. } elseif ( $rsreturn->_numOfRows < $test_nrows ) {
  545. // Rows is less than what we asked for, so must be at the last page.
  546. $atlastpage = true;
  547. }
  548. // Before returning the RecordSet, we set the pagination properties we need
  549. if ($rsreturn) {
  550. $rsreturn->rowsPerPage = $nrows;
  551. $rsreturn->AbsolutePage($page);
  552. $rsreturn->AtFirstPage($atfirstpage);
  553. $rsreturn->AtLastPage($atlastpage);
  554. }
  555. return $rsreturn;
  556. }
  557. function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
  558. {
  559. global $ADODB_QUOTE_FIELDNAMES;
  560. if (!$rs) {
  561. printf(ADODB_BAD_RS,'GetUpdateSQL');
  562. return false;
  563. }
  564. $fieldUpdatedCount = 0;
  565. $arrFields = _array_change_key_case($arrFields);
  566. $hasnumeric = isset($rs->fields[0]);
  567. $setFields = '';
  568. // Loop through all of the fields in the recordset
  569. for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
  570. // Get the field from the recordset
  571. $field = $rs->FetchField($i);
  572. // If the recordset field is one
  573. // of the fields passed in then process.
  574. $upperfname = strtoupper($field->name);
  575. if (adodb_key_exists($upperfname,$arrFields,$force)) {
  576. // If the existing field value in the recordset
  577. // is different from the value passed in then
  578. // go ahead and append the field name and new value to
  579. // the update query.
  580. if ($hasnumeric) $val = $rs->fields[$i];
  581. else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
  582. else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
  583. else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
  584. else $val = '';
  585. if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
  586. // Set the counter for the number of fields that will be updated.
  587. $fieldUpdatedCount++;
  588. // Based on the datatype of the field
  589. // Format the value properly for the database
  590. $type = $rs->MetaType($field->type);
  591. if ($type == 'null') {
  592. $type = 'C';
  593. }
  594. if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) {
  595. switch ($ADODB_QUOTE_FIELDNAMES) {
  596. case 'LOWER':
  597. $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break;
  598. case 'NATIVE':
  599. $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break;
  600. case 'UPPER':
  601. default:
  602. $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break;
  603. }
  604. } else
  605. $fnameq = $upperfname;
  606. //********************************************************//
  607. if (is_null($arrFields[$upperfname])
  608. || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
  609. || $arrFields[$upperfname] === $zthis->null2null
  610. )
  611. {
  612. switch ($force) {
  613. //case 0:
  614. // //Ignore empty values. This is allready handled in "adodb_key_exists" function.
  615. //break;
  616. case 1:
  617. //Set null
  618. $setFields .= $field->name . " = null, ";
  619. break;
  620. case 2:
  621. //Set empty
  622. $arrFields[$upperfname] = "";
  623. $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
  624. break;
  625. default:
  626. case 3:
  627. //Set the value that was given in array, so you can give both null and empty values
  628. if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
  629. $setFields .= $field->name . " = null, ";
  630. } else {
  631. $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
  632. }
  633. break;
  634. }
  635. //********************************************************//
  636. } else {
  637. //we do this so each driver can customize the sql for
  638. //DB specific column types.
  639. //Oracle needs BLOB types to be handled with a returning clause
  640. //postgres has special needs as well
  641. $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
  642. $arrFields, $magicq);
  643. }
  644. }
  645. }
  646. }
  647. // If there were any modified fields then build the rest of the update query.
  648. if ($fieldUpdatedCount > 0 || $forceUpdate) {
  649. // Get the table name from the existing query.
  650. if (!empty($rs->tableName)) $tableName = $rs->tableName;
  651. else {
  652. preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
  653. $tableName = $tableName[1];
  654. }
  655. // Get the full where clause excluding the word "WHERE" from
  656. // the existing query.
  657. preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
  658. $discard = false;
  659. // not a good hack, improvements?
  660. if ($whereClause) {
  661. #var_dump($whereClause);
  662. if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
  663. else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
  664. else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
  665. else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see https://sourceforge.net/p/adodb/bugs/37/
  666. } else
  667. $whereClause = array(false,false);
  668. if ($discard)
  669. $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
  670. $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
  671. if (strlen($whereClause[1]) > 0)
  672. $sql .= ' WHERE '.$whereClause[1];
  673. return $sql;
  674. } else {
  675. return false;
  676. }
  677. }
  678. function adodb_key_exists($key, &$arr,$force=2)
  679. {
  680. if ($force<=0) {
  681. // the following is the old behaviour where null or empty fields are ignored
  682. return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
  683. }
  684. if (isset($arr[$key])) return true;
  685. ## null check below
  686. if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
  687. return false;
  688. }
  689. /**
  690. * There is a special case of this function for the oci8 driver.
  691. * The proper way to handle an insert w/ a blob in oracle requires
  692. * a returning clause with bind variables and a descriptor blob.
  693. *
  694. *
  695. */
  696. function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
  697. {
  698. static $cacheRS = false;
  699. static $cacheSig = 0;
  700. static $cacheCols;
  701. global $ADODB_QUOTE_FIELDNAMES;
  702. $tableName = '';
  703. $values = '';
  704. $fields = '';
  705. $recordSet = null;
  706. $arrFields = _array_change_key_case($arrFields);
  707. $fieldInsertedCount = 0;
  708. if (is_string($rs)) {
  709. //ok we have a table name
  710. //try and get the column info ourself.
  711. $tableName = $rs;
  712. //we need an object for the recordSet
  713. //because we have to call MetaType.
  714. //php can't do a $rsclass::MetaType()
  715. $rsclass = $zthis->rsPrefix.$zthis->databaseType;
  716. $recordSet = new $rsclass(-1,$zthis->fetchMode);
  717. $recordSet->connection = $zthis;
  718. if (is_string($cacheRS) && $cacheRS == $rs) {
  719. $columns = $cacheCols;
  720. } else {
  721. $columns = $zthis->MetaColumns( $tableName );
  722. $cacheRS = $tableName;
  723. $cacheCols = $columns;
  724. }
  725. } else if (is_subclass_of($rs, 'adorecordset')) {
  726. if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
  727. $columns = $cacheCols;
  728. } else {
  729. for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
  730. $columns[] = $rs->FetchField($i);
  731. $cacheRS = $cacheSig;
  732. $cacheCols = $columns;
  733. $rs->insertSig = $cacheSig++;
  734. }
  735. $recordSet = $rs;
  736. } else {
  737. printf(ADODB_BAD_RS,'GetInsertSQL');
  738. return false;
  739. }
  740. // Loop through all of the fields in the recordset
  741. foreach( $columns as $field ) {
  742. $upperfname = strtoupper($field->name);
  743. if (adodb_key_exists($upperfname,$arrFields,$force)) {
  744. $bad = false;
  745. if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) {
  746. switch ($ADODB_QUOTE_FIELDNAMES) {
  747. case 'LOWER':
  748. $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break;
  749. case 'NATIVE':
  750. $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break;
  751. case 'UPPER':
  752. default:
  753. $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break;
  754. }
  755. } else
  756. $fnameq = $upperfname;
  757. $type = $recordSet->MetaType($field->type);
  758. /********************************************************/
  759. if (is_null($arrFields[$upperfname])
  760. || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
  761. || $arrFields[$upperfname] === $zthis->null2null
  762. )
  763. {
  764. switch ($force) {
  765. case 0: // we must always set null if missing
  766. $bad = true;
  767. break;
  768. case 1:
  769. $values .= "null, ";
  770. break;
  771. case 2:
  772. //Set empty
  773. $arrFields[$upperfname] = "";
  774. $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
  775. break;
  776. default:
  777. case 3:
  778. //Set the value that was given in array, so you can give both null and empty values
  779. if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
  780. $values .= "null, ";
  781. } else {
  782. $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
  783. }
  784. break;
  785. } // switch
  786. /*********************************************************/
  787. } else {
  788. //we do this so each driver can customize the sql for
  789. //DB specific column types.
  790. //Oracle needs BLOB types to be handled with a returning clause
  791. //postgres has special needs as well
  792. $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
  793. $arrFields, $magicq);
  794. }
  795. if ($bad) continue;
  796. // Set the counter for the number of fields that will be inserted.
  797. $fieldInsertedCount++;
  798. // Get the name of the fields to insert
  799. $fields .= $fnameq . ", ";
  800. }
  801. }
  802. // If there were any inserted fields then build the rest of the insert query.
  803. if ($fieldInsertedCount <= 0) return false;
  804. // Get the table name from the existing query.
  805. if (!$tableName) {
  806. if (!empty($rs->tableName)) $tableName = $rs->tableName;
  807. else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
  808. $tableName = $tableName[1];
  809. else
  810. return false;
  811. }
  812. // Strip off the comma and space on the end of both the fields
  813. // and their values.
  814. $fields = substr($fields, 0, -2);
  815. $values = substr($values, 0, -2);
  816. // Append the fields and their values to the insert query.
  817. return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )';
  818. }
  819. /**
  820. * This private method is used to help construct
  821. * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
  822. * It handles the string construction of 1 column -> sql string based on
  823. * the column type. We want to do 'safe' handling of BLOBs
  824. *
  825. * @param string the type of sql we are trying to create
  826. * 'I' or 'U'.
  827. * @param string column data type from the db::MetaType() method
  828. * @param string the column name
  829. * @param array the column value
  830. *
  831. * @return string
  832. *
  833. */
  834. function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq)
  835. {
  836. $sql = '';
  837. // Based on the datatype of the field
  838. // Format the value properly for the database
  839. switch($type) {
  840. case 'B':
  841. //in order to handle Blobs correctly, we need
  842. //to do some magic for Oracle
  843. //we need to create a new descriptor to handle
  844. //this properly
  845. if (!empty($zthis->hasReturningInto)) {
  846. if ($action == 'I') {
  847. $sql = 'empty_blob(), ';
  848. } else {
  849. $sql = $fnameq. '=empty_blob(), ';
  850. }
  851. //add the variable to the returning clause array
  852. //so the user can build this later in
  853. //case they want to add more to it
  854. $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
  855. } else if (empty($arrFields[$fname])){
  856. if ($action == 'I') {
  857. $sql = 'empty_blob(), ';
  858. } else {
  859. $sql = $fnameq. '=empty_blob(), ';
  860. }
  861. } else {
  862. //this is to maintain compatibility
  863. //with older adodb versions.
  864. $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
  865. }
  866. break;
  867. case "X":
  868. //we need to do some more magic here for long variables
  869. //to handle these correctly in oracle.
  870. //create a safe bind var name
  871. //to avoid conflicts w/ dupes.
  872. if (!empty($zthis->hasReturningInto)) {
  873. if ($action == 'I') {
  874. $sql = ':xx'.$fname.'xx, ';
  875. } else {
  876. $sql = $fnameq.'=:xx'.$fname.'xx, ';
  877. }
  878. //add the variable to the returning clause array
  879. //so the user can build this later in
  880. //case they want to add more to it
  881. $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
  882. } else {
  883. //this is to maintain compatibility
  884. //with older adodb versions.
  885. $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
  886. }
  887. break;
  888. default:
  889. $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
  890. break;
  891. }
  892. return $sql;
  893. }
  894. function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true)
  895. {
  896. if ($recurse) {
  897. switch($zthis->dataProvider) {
  898. case 'postgres':
  899. if ($type == 'L') $type = 'C';
  900. break;
  901. case 'oci8':
  902. return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
  903. }
  904. }
  905. switch($type) {
  906. case "C":
  907. case "X":
  908. case 'B':
  909. $val = $zthis->qstr($arrFields[$fname],$magicq);
  910. break;
  911. case "D":
  912. $val = $zthis->DBDate($arrFields[$fname]);
  913. break;
  914. case "T":
  915. $val = $zthis->DBTimeStamp($arrFields[$fname]);
  916. break;
  917. case "N":
  918. $val = $arrFields[$fname];
  919. if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
  920. break;
  921. case "I":
  922. case "R":
  923. $val = $arrFields[$fname];
  924. if (!is_numeric($val)) $val = (integer) $val;
  925. break;
  926. default:
  927. $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
  928. if (empty($val)) $val = '0';
  929. break;
  930. }
  931. if ($action == 'I') return $val . ", ";
  932. return $fnameq . "=" . $val . ", ";
  933. }
  934. function _adodb_debug_execute(&$zthis, $sql, $inputarr)
  935. {
  936. $ss = '';
  937. if ($inputarr) {
  938. foreach($inputarr as $kk=>$vv) {
  939. if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
  940. if (is_null($vv)) $ss .= "($kk=>null) ";
  941. else $ss .= "($kk=>'$vv') ";
  942. }
  943. $ss = "[ $ss ]";
  944. }
  945. $sqlTxt = is_array($sql) ? $sql[0] : $sql;
  946. /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
  947. $sqlTxt = str_replace(',',', ',$sqlTxt);
  948. $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
  949. */
  950. // check if running from browser or command-line
  951. $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
  952. $dbt = $zthis->databaseType;
  953. if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
  954. if ($inBrowser) {
  955. if ($ss) {
  956. $ss = '<code>'.htmlspecialchars($ss).'</code>';
  957. }
  958. if ($zthis->debug === -1)
  959. ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br>\n",false);
  960. else if ($zthis->debug !== -99)
  961. ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
  962. } else {
  963. $ss = "\n ".$ss;
  964. if ($zthis->debug !== -99)
  965. ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false);
  966. }
  967. $qID = $zthis->_query($sql,$inputarr);
  968. /*
  969. Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
  970. because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
  971. */
  972. if ($zthis->databaseType == 'mssql') {
  973. // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
  974. if($emsg = $zthis->ErrorMsg()) {
  975. if ($err = $zthis->ErrorNo()) {
  976. if ($zthis->debug === -99)
  977. ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
  978. ADOConnection::outp($err.': '.$emsg);
  979. }
  980. }
  981. } else if (!$qID) {
  982. if ($zthis->debug === -99)
  983. if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
  984. else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false);
  985. ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
  986. }
  987. if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
  988. return $qID;
  989. }
  990. # pretty print the debug_backtrace function
  991. function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null)
  992. {
  993. if (!function_exists('debug_backtrace')) return '';
  994. if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT']));
  995. else $html = $ishtml;
  996. $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
  997. $MAXSTRLEN = 128;
  998. $s = ($html) ? '<pre align=left>' : '';
  999. if (is_array($printOrArr)) $traceArr = $printOrArr;
  1000. else $traceArr = debug_backtrace();
  1001. array_shift($traceArr);
  1002. array_shift($traceArr);
  1003. $tabs = sizeof($traceArr)-2;
  1004. foreach ($traceArr as $arr) {
  1005. if ($skippy) {$skippy -= 1; continue;}
  1006. $levels -= 1;
  1007. if ($levels < 0) break;
  1008. $args = array();
  1009. for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' &nbsp; ' : "\t";
  1010. $tabs -= 1;
  1011. if ($html) $s .= '<font face="Courier New,Courier">';
  1012. if (isset($arr['class'])) $s .= $arr['class'].'.';
  1013. if (isset($arr['args']))
  1014. foreach($arr['args'] as $v) {
  1015. if (is_null($v)) $args[] = 'null';
  1016. else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
  1017. else if (is_object($v)) $args[] = 'Object:'.get_class($v);
  1018. else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
  1019. else {
  1020. $v = (string) @$v;
  1021. $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN)));
  1022. if (strlen($v) > $MAXSTRLEN) $str .= '...';
  1023. $args[] = $str;
  1024. }
  1025. }
  1026. $s .= $arr['function'].'('.implode(', ',$args).')';
  1027. $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
  1028. $s .= "\n";
  1029. }
  1030. if ($html) $s .= '</pre>';
  1031. if ($printOrArr) print $s;
  1032. return $s;
  1033. }
  1034. /*
  1035. function _adodb_find_from($sql)
  1036. {
  1037. $sql = str_replace(array("\n","\r"), ' ', $sql);
  1038. $charCount = strlen($sql);
  1039. $inString = false;
  1040. $quote = '';
  1041. $parentheseCount = 0;
  1042. $prevChars = '';
  1043. $nextChars = '';
  1044. for($i = 0; $i < $charCount; $i++) {
  1045. $char = substr($sql,$i,1);
  1046. $prevChars = substr($sql,0,$i);
  1047. $nextChars = substr($sql,$i+1);
  1048. if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
  1049. $quote = $char;
  1050. $inString = true;
  1051. }
  1052. elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
  1053. $quote = "";
  1054. $inString = false;
  1055. }
  1056. elseif($char == "(" && $inString === false)
  1057. $parentheseCount++;
  1058. elseif($char == ")" && $inString === false && $parentheseCount > 0)
  1059. $parentheseCount--;
  1060. elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
  1061. return $i;
  1062. }
  1063. }
  1064. */