Fixes to the PaintWeb cron task.
[moodle/mihaisucan.git] / lib / adodb / adodb-lib.inc.php
blob1e1e7e3d5d25f8282edf9536d1db39bdbe634b3b
1 <?php
3 // security - hide paths
4 if (!defined('ADODB_DIR')) die();
6 global $ADODB_INCLUDED_LIB;
7 $ADODB_INCLUDED_LIB = 1;
9 /*
10 @version V4.98 13 Feb 2008 (c) 2000-2008 John Lim (jlim\@natsoft.com.my). All rights reserved.
11 Released under both BSD license and Lesser GPL library license.
12 Whenever there is any discrepancy between the two licenses,
13 the BSD license will take precedence. See License.txt.
14 Set tabs to 4 for best viewing.
16 Less commonly used functions are placed here to reduce size of adodb.inc.php.
17 */
19 function adodb_strip_order_by($sql)
21 $rez = preg_match('/(\sORDER\s+BY\s[^)]*)/is',$sql,$arr);
22 if ($arr)
23 if (strpos($arr[0],'(') !== false) {
24 $at = strpos($sql,$arr[0]);
25 $cntin = 0;
26 for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
27 $ch = $sql[$i];
28 if ($ch == '(') {
29 $cntin += 1;
30 } elseif($ch == ')') {
31 $cntin -= 1;
32 if ($cntin < 0) {
33 break;
37 $sql = substr($sql,0,$at).substr($sql,$i);
38 } else
39 $sql = str_replace($arr[0], '', $sql);
40 return $sql;
43 if (false) {
44 $sql = 'select * from (select a from b order by a(b),b(c) desc)';
45 $sql = '(select * from abc order by 1)';
46 die(adodb_strip_order_by($sql));
49 function adodb_probetypes(&$array,&$types,$probe=8)
51 // probe and guess the type
52 $types = array();
53 if ($probe > sizeof($array)) $max = sizeof($array);
54 else $max = $probe;
57 for ($j=0;$j < $max; $j++) {
58 $row =& $array[$j];
59 if (!$row) break;
60 $i = -1;
61 foreach($row as $v) {
62 $i += 1;
64 if (isset($types[$i]) && $types[$i]=='C') continue;
66 //print " ($i ".$types[$i]. "$v) ";
67 $v = trim($v);
69 if (!preg_match('/^[+-]{0,1}[0-9\.]+$/',$v)) {
70 $types[$i] = 'C'; // once C, always C
72 continue;
74 if ($j == 0) {
75 // If empty string, we presume is character
76 // test for integer for 1st row only
77 // after that it is up to testing other rows to prove
78 // that it is not an integer
79 if (strlen($v) == 0) $types[$i] = 'C';
80 if (strpos($v,'.') !== false) $types[$i] = 'N';
81 else $types[$i] = 'I';
82 continue;
85 if (strpos($v,'.') !== false) $types[$i] = 'N';
92 function adodb_transpose(&$arr, &$newarr, &$hdr, &$fobjs)
94 $oldX = sizeof(reset($arr));
95 $oldY = sizeof($arr);
97 if ($hdr) {
98 $startx = 1;
99 $hdr = array('Fields');
100 for ($y = 0; $y < $oldY; $y++) {
101 $hdr[] = $arr[$y][0];
103 } else
104 $startx = 0;
106 for ($x = $startx; $x < $oldX; $x++) {
107 if ($fobjs) {
108 $o = $fobjs[$x];
109 $newarr[] = array($o->name);
110 } else
111 $newarr[] = array();
113 for ($y = 0; $y < $oldY; $y++) {
114 $newarr[$x-$startx][] = $arr[$y][$x];
119 // Force key to upper.
120 // See also http://www.php.net/manual/en/function.array-change-key-case.php
121 function _array_change_key_case($an_array)
123 if (is_array($an_array)) {
124 $new_array = array();
125 foreach($an_array as $key=>$value)
126 $new_array[strtoupper($key)] = $value;
128 return $new_array;
131 return $an_array;
134 function _adodb_replace(&$zthis, $table, $fieldArray, $keyCol, $autoQuote, $has_autoinc)
136 if (count($fieldArray) == 0) return 0;
137 $first = true;
138 $uSet = '';
140 if (!is_array($keyCol)) {
141 $keyCol = array($keyCol);
143 foreach($fieldArray as $k => $v) {
144 if ($v === null) {
145 $v = 'NULL';
146 $fieldArray[$k] = $v;
147 } else if ($autoQuote && !is_numeric($v) /*and strncmp($v,"'",1) !== 0 -- sql injection risk*/ and strcasecmp($v,$zthis->null2null)!=0) {
148 $v = $zthis->qstr($v);
149 $fieldArray[$k] = $v;
151 if (in_array($k,$keyCol)) continue; // skip UPDATE if is key
153 if ($first) {
154 $first = false;
155 $uSet = "$k=$v";
156 } else
157 $uSet .= ",$k=$v";
160 $where = false;
161 foreach ($keyCol as $v) {
162 if (isset($fieldArray[$v])) {
163 if ($where) $where .= ' and '.$v.'='.$fieldArray[$v];
164 else $where = $v.'='.$fieldArray[$v];
168 if ($uSet && $where) {
169 $update = "UPDATE $table SET $uSet WHERE $where";
171 $rs = $zthis->Execute($update);
174 if ($rs) {
175 if ($zthis->poorAffectedRows) {
177 The Select count(*) wipes out any errors that the update would have returned.
178 http://phplens.com/lens/lensforum/msgs.php?id=5696
180 if ($zthis->ErrorNo()<>0) return 0;
182 # affected_rows == 0 if update field values identical to old values
183 # for mysql - which is silly.
185 $cnt = $zthis->GetOne("select count(*) from $table where $where");
186 if ($cnt > 0) return 1; // record already exists
187 } else {
188 if (($zthis->Affected_Rows()>0)) return 1;
190 } else
191 return 0;
194 // print "<p>Error=".$this->ErrorNo().'<p>';
195 $first = true;
196 foreach($fieldArray as $k => $v) {
197 if ($has_autoinc && in_array($k,$keyCol)) continue; // skip autoinc col
199 if ($first) {
200 $first = false;
201 $iCols = "$k";
202 $iVals = "$v";
203 } else {
204 $iCols .= ",$k";
205 $iVals .= ",$v";
208 $insert = "INSERT INTO $table ($iCols) VALUES ($iVals)";
209 $rs = $zthis->Execute($insert);
210 return ($rs) ? 2 : 0;
213 // Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
214 function _adodb_getmenu(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
215 $size=0, $selectAttr='',$compareFields0=true)
217 $hasvalue = false;
219 if ($multiple or is_array($defstr)) {
220 if ($size==0) $size=5;
221 $attr = ' multiple size="'.$size.'"';
222 if (!strpos($name,'[]')) $name .= '[]';
223 } else if ($size) $attr = ' size="'.$size.'"';
224 else $attr ='';
226 $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
227 if ($blank1stItem)
228 if (is_string($blank1stItem)) {
229 $barr = explode(':',$blank1stItem);
230 if (sizeof($barr) == 1) $barr[] = '';
231 $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
232 } else $s .= "\n<option></option>";
234 if ($zthis->FieldCount() > 1) $hasvalue=true;
235 else $compareFields0 = true;
237 $value = '';
238 $optgroup = null;
239 $firstgroup = true;
240 $fieldsize = $zthis->FieldCount();
241 while(!$zthis->EOF) {
242 $zval = rtrim(reset($zthis->fields));
244 if ($blank1stItem && $zval=="") {
245 $zthis->MoveNext();
246 continue;
249 if ($fieldsize > 1) {
250 if (isset($zthis->fields[1]))
251 $zval2 = rtrim($zthis->fields[1]);
252 else
253 $zval2 = rtrim(next($zthis->fields));
255 $selected = ($compareFields0) ? $zval : $zval2;
257 $group = '';
258 if ($fieldsize > 2) {
259 $group = rtrim($zthis->fields[2]);
262 if ($optgroup != $group) {
263 $optgroup = $group;
264 if ($firstgroup) {
265 $firstgroup = false;
266 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
267 } else {
268 $s .="\n</optgroup>";
269 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
273 if ($hasvalue)
274 $value = " value='".htmlspecialchars($zval2)."'";
276 if (is_array($defstr)) {
278 if (in_array($selected,$defstr))
279 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
280 else
281 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
283 else {
284 if (strcasecmp($selected,$defstr)==0)
285 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
286 else
287 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
289 $zthis->MoveNext();
290 } // while
292 // closing last optgroup
293 if($optgroup != null) {
294 $s .= "\n</optgroup>";
296 return $s ."\n</select>\n";
299 // Requires $ADODB_FETCH_MODE = ADODB_FETCH_NUM
300 function _adodb_getmenu_gp(&$zthis, $name,$defstr='',$blank1stItem=true,$multiple=false,
301 $size=0, $selectAttr='',$compareFields0=true)
303 $hasvalue = false;
305 if ($multiple or is_array($defstr)) {
306 if ($size==0) $size=5;
307 $attr = ' multiple size="'.$size.'"';
308 if (!strpos($name,'[]')) $name .= '[]';
309 } else if ($size) $attr = ' size="'.$size.'"';
310 else $attr ='';
312 $s = '<select name="'.$name.'"'.$attr.' '.$selectAttr.'>';
313 if ($blank1stItem)
314 if (is_string($blank1stItem)) {
315 $barr = explode(':',$blank1stItem);
316 if (sizeof($barr) == 1) $barr[] = '';
317 $s .= "\n<option value=\"".$barr[0]."\">".$barr[1]."</option>";
318 } else $s .= "\n<option></option>";
320 if ($zthis->FieldCount() > 1) $hasvalue=true;
321 else $compareFields0 = true;
323 $value = '';
324 $optgroup = null;
325 $firstgroup = true;
326 $fieldsize = sizeof($zthis->fields);
327 while(!$zthis->EOF) {
328 $zval = rtrim(reset($zthis->fields));
330 if ($blank1stItem && $zval=="") {
331 $zthis->MoveNext();
332 continue;
335 if ($fieldsize > 1) {
336 if (isset($zthis->fields[1]))
337 $zval2 = rtrim($zthis->fields[1]);
338 else
339 $zval2 = rtrim(next($zthis->fields));
341 $selected = ($compareFields0) ? $zval : $zval2;
343 $group = '';
344 if (isset($zthis->fields[2])) {
345 $group = rtrim($zthis->fields[2]);
348 if ($optgroup != $group) {
349 $optgroup = $group;
350 if ($firstgroup) {
351 $firstgroup = false;
352 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
353 } else {
354 $s .="\n</optgroup>";
355 $s .="\n<optgroup label='". htmlspecialchars($group) ."'>";
359 if ($hasvalue)
360 $value = " value='".htmlspecialchars($zval2)."'";
362 if (is_array($defstr)) {
364 if (in_array($selected,$defstr))
365 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
366 else
367 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
369 else {
370 if (strcasecmp($selected,$defstr)==0)
371 $s .= "\n<option selected='selected'$value>".htmlspecialchars($zval).'</option>';
372 else
373 $s .= "\n<option".$value.'>'.htmlspecialchars($zval).'</option>';
375 $zthis->MoveNext();
376 } // while
378 // closing last optgroup
379 if($optgroup != null) {
380 $s .= "\n</optgroup>";
382 return $s ."\n</select>\n";
387 Count the number of records this sql statement will return by using
388 query rewriting heuristics...
390 Does not work with UNIONs, except with postgresql and oracle.
392 Usage:
394 $conn->Connect(...);
395 $cnt = _adodb_getcount($conn, $sql);
398 function _adodb_getcount(&$zthis, $sql,$inputarr=false,$secs2cache=0)
400 $qryRecs = 0;
402 if (!empty($zthis->_nestedSQL) || preg_match("/^\s*SELECT\s+DISTINCT/is", $sql) ||
403 preg_match('/\s+GROUP\s+BY\s+/is',$sql) ||
404 preg_match('/\s+UNION\s+/is',$sql)) {
406 $rewritesql = adodb_strip_order_by($sql);
408 // ok, has SELECT DISTINCT or GROUP BY so see if we can use a table alias
409 // but this is only supported by oracle and postgresql...
410 if ($zthis->dataProvider == 'oci8') {
411 // Allow Oracle hints to be used for query optimization, Chris Wrye
412 if (preg_match('#/\\*+.*?\\*\\/#', $sql, $hint)) {
413 $rewritesql = "SELECT ".$hint[0]." COUNT(*) FROM (".$rewritesql.")";
414 } else
415 $rewritesql = "SELECT COUNT(*) FROM (".$rewritesql.")";
417 } else if (strncmp($zthis->databaseType,'postgres',8) == 0 || strncmp($zthis->databaseType,'mysql',5) == 0) {
418 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) _ADODB_ALIAS_";
419 } else {
420 $rewritesql = "SELECT COUNT(*) FROM ($rewritesql) ";
422 } else {
423 // now replace SELECT ... FROM with SELECT COUNT(*) FROM
424 $rewritesql = preg_replace(
425 '/^\s*SELECT\s.*\s+FROM\s/Uis','SELECT COUNT(*) FROM ',$sql);
426 // fix by alexander zhukov, alex#unipack.ru, because count(*) and 'order by' fails
427 // with mssql, access and postgresql. Also a good speedup optimization - skips sorting!
428 // also see http://phplens.com/lens/lensforum/msgs.php?id=12752
429 $rewritesql = adodb_strip_order_by($rewritesql);
432 if (isset($rewritesql) && $rewritesql != $sql) {
433 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
435 if ($secs2cache) {
436 // we only use half the time of secs2cache because the count can quickly
437 // become inaccurate if new records are added
438 $qryRecs = $zthis->CacheGetOne($secs2cache/2,$rewritesql,$inputarr);
440 } else {
441 $qryRecs = $zthis->GetOne($rewritesql,$inputarr);
443 if ($qryRecs !== false) return $qryRecs;
445 //--------------------------------------------
446 // query rewrite failed - so try slower way...
449 // strip off unneeded ORDER BY if no UNION
450 if (preg_match('/\s*UNION\s*/is', $sql)) $rewritesql = $sql;
451 else $rewritesql = $rewritesql = adodb_strip_order_by($sql);
453 if (preg_match('/\sLIMIT\s+[0-9]+/i',$sql,$limitarr)) $rewritesql .= $limitarr[0];
455 $rstest = &$zthis->Execute($rewritesql,$inputarr);
456 if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
458 if ($rstest) {
459 $qryRecs = $rstest->RecordCount();
460 if ($qryRecs == -1) {
461 global $ADODB_EXTENSION;
462 // some databases will return -1 on MoveLast() - change to MoveNext()
463 if ($ADODB_EXTENSION) {
464 while(!$rstest->EOF) {
465 adodb_movenext($rstest);
467 } else {
468 while(!$rstest->EOF) {
469 $rstest->MoveNext();
472 $qryRecs = $rstest->_currentRow;
474 $rstest->Close();
475 if ($qryRecs == -1) return 0;
477 return $qryRecs;
481 Code originally from "Cornel G" <conyg@fx.ro>
483 This code might not work with SQL that has UNION in it
485 Also if you are using CachePageExecute(), there is a strong possibility that
486 data will get out of synch. use CachePageExecute() only with tables that
487 rarely change.
489 function &_adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
490 $inputarr=false, $secs2cache=0)
492 $atfirstpage = false;
493 $atlastpage = false;
494 $lastpageno=1;
496 // If an invalid nrows is supplied,
497 // we assume a default value of 10 rows per page
498 if (!isset($nrows) || $nrows <= 0) $nrows = 10;
500 $qryRecs = false; //count records for no offset
502 $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
503 $lastpageno = (int) ceil($qryRecs / $nrows);
504 $zthis->_maxRecordCount = $qryRecs;
508 // ***** Here we check whether $page is the last page or
509 // whether we are trying to retrieve
510 // a page number greater than the last page number.
511 if ($page >= $lastpageno) {
512 $page = $lastpageno;
513 $atlastpage = true;
516 // If page number <= 1, then we are at the first page
517 if (empty($page) || $page <= 1) {
518 $page = 1;
519 $atfirstpage = true;
522 // We get the data we want
523 $offset = $nrows * ($page-1);
524 if ($secs2cache > 0)
525 $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
526 else
527 $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
530 // Before returning the RecordSet, we set the pagination properties we need
531 if ($rsreturn) {
532 $rsreturn->_maxRecordCount = $qryRecs;
533 $rsreturn->rowsPerPage = $nrows;
534 $rsreturn->AbsolutePage($page);
535 $rsreturn->AtFirstPage($atfirstpage);
536 $rsreturn->AtLastPage($atlastpage);
537 $rsreturn->LastPageNo($lastpageno);
539 return $rsreturn;
542 // Iván Oliva version
543 function &_adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
546 $atfirstpage = false;
547 $atlastpage = false;
549 if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page
550 $page = 1;
551 $atfirstpage = true;
553 if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page
555 // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than
556 // the last page number.
557 $pagecounter = $page + 1;
558 $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
559 if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
560 else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
561 if ($rstest) {
562 while ($rstest && $rstest->EOF && $pagecounter>0) {
563 $atlastpage = true;
564 $pagecounter--;
565 $pagecounteroffset = $nrows * ($pagecounter - 1);
566 $rstest->Close();
567 if ($secs2cache>0) $rstest = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
568 else $rstest = &$zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
570 if ($rstest) $rstest->Close();
572 if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it
573 $page = $pagecounter;
574 if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first
575 //... page, that is, the recordset has only 1 page.
578 // We get the data we want
579 $offset = $nrows * ($page-1);
580 if ($secs2cache > 0) $rsreturn = &$zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
581 else $rsreturn = &$zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
583 // Before returning the RecordSet, we set the pagination properties we need
584 if ($rsreturn) {
585 $rsreturn->rowsPerPage = $nrows;
586 $rsreturn->AbsolutePage($page);
587 $rsreturn->AtFirstPage($atfirstpage);
588 $rsreturn->AtLastPage($atlastpage);
590 return $rsreturn;
593 function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
595 global $ADODB_QUOTE_FIELDNAMES;
597 if (!$rs) {
598 printf(ADODB_BAD_RS,'GetUpdateSQL');
599 return false;
602 $fieldUpdatedCount = 0;
603 $arrFields = _array_change_key_case($arrFields);
605 $hasnumeric = isset($rs->fields[0]);
606 $setFields = '';
608 // Loop through all of the fields in the recordset
609 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
610 // Get the field from the recordset
611 $field = $rs->FetchField($i);
613 // If the recordset field is one
614 // of the fields passed in then process.
615 $upperfname = strtoupper($field->name);
616 if (adodb_key_exists($upperfname,$arrFields,$force)) {
618 // If the existing field value in the recordset
619 // is different from the value passed in then
620 // go ahead and append the field name and new value to
621 // the update query.
623 if ($hasnumeric) $val = $rs->fields[$i];
624 else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
625 else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
626 else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
627 else $val = '';
630 if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
631 // Set the counter for the number of fields that will be updated.
632 $fieldUpdatedCount++;
634 // Based on the datatype of the field
635 // Format the value properly for the database
636 $type = $rs->MetaType($field->type);
639 if ($type == 'null') {
640 $type = 'C';
643 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
644 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
645 else
646 $fnameq = $upperfname;
649 // is_null requires php 4.0.4
650 //********************************************************//
651 if (is_null($arrFields[$upperfname])
652 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
653 || $arrFields[$upperfname] === $zthis->null2null
656 switch ($force) {
658 //case 0:
659 // //Ignore empty values. This is allready handled in "adodb_key_exists" function.
660 //break;
662 case 1:
663 //Set null
664 $setFields .= $field->name . " = null, ";
665 break;
667 case 2:
668 //Set empty
669 $arrFields[$upperfname] = "";
670 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
671 break;
672 default:
673 case 3:
674 //Set the value that was given in array, so you can give both null and empty values
675 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
676 $setFields .= $field->name . " = null, ";
677 } else {
678 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
680 break;
682 //********************************************************//
683 } else {
684 //we do this so each driver can customize the sql for
685 //DB specific column types.
686 //Oracle needs BLOB types to be handled with a returning clause
687 //postgres has special needs as well
688 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
689 $arrFields, $magicq);
695 // If there were any modified fields then build the rest of the update query.
696 if ($fieldUpdatedCount > 0 || $forceUpdate) {
697 // Get the table name from the existing query.
698 if (!empty($rs->tableName)) $tableName = $rs->tableName;
699 else {
700 preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
701 $tableName = $tableName[1];
703 // Get the full where clause excluding the word "WHERE" from
704 // the existing query.
705 preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
707 $discard = false;
708 // not a good hack, improvements?
709 if ($whereClause) {
710 #var_dump($whereClause);
711 if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
712 else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
713 else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
714 else preg_match('/\s.*(\) WHERE .*)/is', $whereClause[1], $discard); # see http://sourceforge.net/tracker/index.php?func=detail&aid=1379638&group_id=42718&atid=433976
715 } else
716 $whereClause = array(false,false);
718 if ($discard)
719 $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
721 $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
722 if (strlen($whereClause[1]) > 0)
723 $sql .= ' WHERE '.$whereClause[1];
725 return $sql;
727 } else {
728 return false;
732 function adodb_key_exists($key, &$arr,$force=2)
734 if ($force<=0) {
735 // the following is the old behaviour where null or empty fields are ignored
736 return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
739 if (isset($arr[$key])) return true;
740 ## null check below
741 if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
742 return false;
746 * There is a special case of this function for the oci8 driver.
747 * The proper way to handle an insert w/ a blob in oracle requires
748 * a returning clause with bind variables and a descriptor blob.
752 function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
754 static $cacheRS = false;
755 static $cacheSig = 0;
756 static $cacheCols;
757 global $ADODB_QUOTE_FIELDNAMES;
759 $tableName = '';
760 $values = '';
761 $fields = '';
762 $recordSet = null;
763 $arrFields = _array_change_key_case($arrFields);
764 $fieldInsertedCount = 0;
766 if (is_string($rs)) {
767 //ok we have a table name
768 //try and get the column info ourself.
769 $tableName = $rs;
771 //we need an object for the recordSet
772 //because we have to call MetaType.
773 //php can't do a $rsclass::MetaType()
774 $rsclass = $zthis->rsPrefix.$zthis->databaseType;
775 $recordSet = new $rsclass(-1,$zthis->fetchMode);
776 $recordSet->connection = &$zthis;
778 if (is_string($cacheRS) && $cacheRS == $rs) {
779 $columns =& $cacheCols;
780 } else {
781 $columns = $zthis->MetaColumns( $tableName );
782 $cacheRS = $tableName;
783 $cacheCols = $columns;
785 } else if (is_subclass_of($rs, 'adorecordset')) {
786 if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
787 $columns =& $cacheCols;
788 } else {
789 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
790 $columns[] = $rs->FetchField($i);
791 $cacheRS = $cacheSig;
792 $cacheCols = $columns;
793 $rs->insertSig = $cacheSig++;
795 $recordSet =& $rs;
797 } else {
798 printf(ADODB_BAD_RS,'GetInsertSQL');
799 return false;
802 // Loop through all of the fields in the recordset
803 foreach( $columns as $field ) {
804 $upperfname = strtoupper($field->name);
805 if (adodb_key_exists($upperfname,$arrFields,$force)) {
806 $bad = false;
807 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES))
808 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;
809 else
810 $fnameq = $upperfname;
812 $type = $recordSet->MetaType($field->type);
814 /********************************************************/
815 if (is_null($arrFields[$upperfname])
816 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
817 || $arrFields[$upperfname] === $zthis->null2null
820 switch ($force) {
822 case 0: // we must always set null if missing
823 $bad = true;
824 break;
826 case 1:
827 $values .= "null, ";
828 break;
830 case 2:
831 //Set empty
832 $arrFields[$upperfname] = "";
833 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
834 break;
836 default:
837 case 3:
838 //Set the value that was given in array, so you can give both null and empty values
839 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
840 $values .= "null, ";
841 } else {
842 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
844 break;
845 } // switch
847 /*********************************************************/
848 } else {
849 //we do this so each driver can customize the sql for
850 //DB specific column types.
851 //Oracle needs BLOB types to be handled with a returning clause
852 //postgres has special needs as well
853 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
854 $arrFields, $magicq);
857 if ($bad) continue;
858 // Set the counter for the number of fields that will be inserted.
859 $fieldInsertedCount++;
862 // Get the name of the fields to insert
863 $fields .= $fnameq . ", ";
868 // If there were any inserted fields then build the rest of the insert query.
869 if ($fieldInsertedCount <= 0) return false;
871 // Get the table name from the existing query.
872 if (!$tableName) {
873 if (!empty($rs->tableName)) $tableName = $rs->tableName;
874 else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
875 $tableName = $tableName[1];
876 else
877 return false;
880 // Strip off the comma and space on the end of both the fields
881 // and their values.
882 $fields = substr($fields, 0, -2);
883 $values = substr($values, 0, -2);
885 // Append the fields and their values to the insert query.
886 return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )';
891 * This private method is used to help construct
892 * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
893 * It handles the string construction of 1 column -> sql string based on
894 * the column type. We want to do 'safe' handling of BLOBs
896 * @param string the type of sql we are trying to create
897 * 'I' or 'U'.
898 * @param string column data type from the db::MetaType() method
899 * @param string the column name
900 * @param array the column value
902 * @return string
905 function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq)
907 $sql = '';
909 // Based on the datatype of the field
910 // Format the value properly for the database
911 switch($type) {
912 case 'B':
913 //in order to handle Blobs correctly, we need
914 //to do some magic for Oracle
916 //we need to create a new descriptor to handle
917 //this properly
918 if (!empty($zthis->hasReturningInto)) {
919 if ($action == 'I') {
920 $sql = 'empty_blob(), ';
921 } else {
922 $sql = $fnameq. '=empty_blob(), ';
924 //add the variable to the returning clause array
925 //so the user can build this later in
926 //case they want to add more to it
927 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
928 } else if (empty($arrFields[$fname])){
929 if ($action == 'I') {
930 $sql = 'empty_blob(), ';
931 } else {
932 $sql = $fnameq. '=empty_blob(), ';
934 } else {
935 //this is to maintain compatibility
936 //with older adodb versions.
937 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
939 break;
941 case "X":
942 //we need to do some more magic here for long variables
943 //to handle these correctly in oracle.
945 //create a safe bind var name
946 //to avoid conflicts w/ dupes.
947 if (!empty($zthis->hasReturningInto)) {
948 if ($action == 'I') {
949 $sql = ':xx'.$fname.'xx, ';
950 } else {
951 $sql = $fnameq.'=:xx'.$fname.'xx, ';
953 //add the variable to the returning clause array
954 //so the user can build this later in
955 //case they want to add more to it
956 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
957 } else {
958 //this is to maintain compatibility
959 //with older adodb versions.
960 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
962 break;
964 default:
965 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
966 break;
969 return $sql;
972 function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true)
975 if ($recurse) {
976 switch($zthis->dataProvider) {
977 case 'postgres':
978 if ($type == 'L') $type = 'C';
979 break;
980 case 'oci8':
981 return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
986 switch($type) {
987 case "C":
988 case "X":
989 case 'B':
990 $val = $zthis->qstr($arrFields[$fname],$magicq);
991 break;
993 case "D":
994 $val = $zthis->DBDate($arrFields[$fname]);
995 break;
997 case "T":
998 $val = $zthis->DBTimeStamp($arrFields[$fname]);
999 break;
1001 case "F": //Floating point number // Moodle added
1002 case "N":
1003 $val = $arrFields[$fname];
1004 if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
1005 break;
1007 case "L": //Integer field suitable for storing booleans (0 or 1) // Moodle added
1008 case "I":
1009 case "R":
1010 $val = $arrFields[$fname];
1011 if (!is_numeric($val)) $val = (integer) $val;
1012 break;
1014 default:
1015 $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
1016 if (empty($val)) $val = '0';
1017 break;
1020 if ($action == 'I') return $val . ", ";
1023 return $fnameq . "=" . $val . ", ";
1029 function _adodb_debug_execute(&$zthis, $sql, $inputarr)
1031 $ss = '';
1032 if ($inputarr) {
1033 foreach($inputarr as $kk=>$vv) {
1034 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
1035 if (is_null($vv)) $ss .= "($kk=>null) ";
1036 else $ss .= "($kk=>'$vv') ";
1038 $ss = "[ $ss ]";
1040 $sqlTxt = is_array($sql) ? $sql[0] : $sql;
1041 /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
1042 $sqlTxt = str_replace(',',', ',$sqlTxt);
1043 $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
1045 // check if running from browser or command-line
1046 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1048 $dbt = $zthis->databaseType;
1049 if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
1050 if ($inBrowser) {
1051 if ($ss) {
1052 $ss = '<code>'.htmlspecialchars($ss).'</code>';
1054 if ($zthis->debug === -1)
1055 ADOConnection::outp( "<br />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br />\n",false);
1056 else
1057 ADOConnection::outp( "<hr />\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr />\n",false);
1058 } else {
1059 ADOConnection::outp("-----\n($dbt): ".$sqlTxt."\n-----\n",false);
1062 $qID = $zthis->_query($sql,$inputarr);
1065 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
1066 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
1068 if ($zthis->databaseType == 'mssql') {
1069 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
1070 if($emsg = $zthis->ErrorMsg()) {
1071 if ($err = $zthis->ErrorNo()) ADOConnection::outp($err.': '.$emsg);
1073 } else if (!$qID) {
1074 ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
1077 if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
1078 return $qID;
1081 # pretty print the debug_backtrace function
1082 function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0)
1084 if (!function_exists('debug_backtrace')) return '';
1086 $html = (isset($_SERVER['HTTP_USER_AGENT']));
1087 // moodle change start - see readme_moodle.txt
1088 $fmt = ($html) ? "</font><font color=\"#808080\" size=\"-1\"> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
1089 // moodle change end
1091 $MAXSTRLEN = 128;
1093 // moodle change start - see readme_moodle.txt
1094 $s = ($html) ? '<pre align="left">' : '';
1095 // moodle change end
1097 if (is_array($printOrArr)) $traceArr = $printOrArr;
1098 else $traceArr = debug_backtrace();
1099 array_shift($traceArr);
1100 array_shift($traceArr);
1101 $tabs = sizeof($traceArr)-2;
1103 foreach ($traceArr as $arr) {
1104 if ($skippy) {$skippy -= 1; continue;}
1105 $levels -= 1;
1106 if ($levels < 0) break;
1108 $args = array();
1109 for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' &nbsp; ' : "\t";
1110 $tabs -= 1;
1111 if ($html) $s .= '<font face="Courier New,Courier">';
1112 if (isset($arr['class'])) $s .= $arr['class'].'.';
1113 if (isset($arr['args']))
1114 foreach($arr['args'] as $v) {
1115 if (is_null($v)) $args[] = 'null';
1116 else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
1117 else if (is_object($v)) $args[] = 'Object:'.get_class($v);
1118 else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
1119 else {
1120 $v = (string) @$v;
1121 $str = htmlspecialchars(substr($v,0,$MAXSTRLEN));
1122 if (strlen($v) > $MAXSTRLEN) $str .= '...';
1123 $args[] = $str;
1126 $s .= $arr['function'].'('.implode(', ',$args).')';
1129 $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
1131 $s .= "\n";
1133 if ($html) $s .= '</pre>';
1134 if ($printOrArr) print $s;
1136 return $s;
1139 function _adodb_find_from($sql)
1142 $sql = str_replace(array("\n","\r"), ' ', $sql);
1143 $charCount = strlen($sql);
1145 $inString = false;
1146 $quote = '';
1147 $parentheseCount = 0;
1148 $prevChars = '';
1149 $nextChars = '';
1152 for($i = 0; $i < $charCount; $i++) {
1154 $char = substr($sql,$i,1);
1155 $prevChars = substr($sql,0,$i);
1156 $nextChars = substr($sql,$i+1);
1158 if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
1159 $quote = $char;
1160 $inString = true;
1163 elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
1164 $quote = "";
1165 $inString = false;
1168 elseif($char == "(" && $inString === false)
1169 $parentheseCount++;
1171 elseif($char == ")" && $inString === false && $parentheseCount > 0)
1172 $parentheseCount--;
1174 elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
1175 return $i;