Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 3.9.x will end* 10 May 2021 (12 months).
  • Bug fixes for security issues in 3.9.x will end* 8 May 2023 (36 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]

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