MDL-52808 calendar: Do not return events for hidden activities
[moodle.git] / lib / adodb / adodb-lib.inc.php
blobde35bc983da4bfbd6eb3284c9c8e40d4a616cafe
1 <?php
2 // security - hide paths
3 if (!defined('ADODB_DIR')) die();
5 global $ADODB_INCLUDED_LIB;
6 $ADODB_INCLUDED_LIB = 1;
8 /*
9 @version V5.19 23-Apr-2014 (c) 2000-2014 John Lim (jlim#natsoft.com). All rights reserved.
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.
15 Less commonly used functions are placed here to reduce size of adodb.inc.php.
18 function adodb_strip_order_by($sql)
20 $rez = preg_match('/(\sORDER\s+BY\s(?:[^)](?!limit))*)(?:\sLIMIT\s+[0-9]+)?/is', $sql, $arr);
21 if ($arr)
22 if (strpos($arr[1], '(') !== false) {
23 $at = strpos($sql, $arr[1]);
24 $cntin = 0;
25 for ($i=$at, $max=strlen($sql); $i < $max; $i++) {
26 $ch = $sql[$i];
27 if ($ch == '(') {
28 $cntin += 1;
29 } elseif($ch == ')') {
30 $cntin -= 1;
31 if ($cntin < 0) {
32 break;
36 $sql = substr($sql,0,$at).substr($sql,$i);
37 } else {
38 $sql = str_replace($arr[1], '', $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*/ 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 if ($secs2cache) {
456 $rstest = $zthis->CacheExecute($secs2cache,$rewritesql,$inputarr);
457 if (!$rstest) $rstest = $zthis->CacheExecute($secs2cache,$sql,$inputarr);
458 } else {
459 $rstest = $zthis->Execute($rewritesql,$inputarr);
460 if (!$rstest) $rstest = $zthis->Execute($sql,$inputarr);
462 if ($rstest) {
463 $qryRecs = $rstest->RecordCount();
464 if ($qryRecs == -1) {
465 global $ADODB_EXTENSION;
466 // some databases will return -1 on MoveLast() - change to MoveNext()
467 if ($ADODB_EXTENSION) {
468 while(!$rstest->EOF) {
469 adodb_movenext($rstest);
471 } else {
472 while(!$rstest->EOF) {
473 $rstest->MoveNext();
476 $qryRecs = $rstest->_currentRow;
478 $rstest->Close();
479 if ($qryRecs == -1) return 0;
481 return $qryRecs;
485 Code originally from "Cornel G" <conyg@fx.ro>
487 This code might not work with SQL that has UNION in it
489 Also if you are using CachePageExecute(), there is a strong possibility that
490 data will get out of synch. use CachePageExecute() only with tables that
491 rarely change.
493 function _adodb_pageexecute_all_rows(&$zthis, $sql, $nrows, $page,
494 $inputarr=false, $secs2cache=0)
496 $atfirstpage = false;
497 $atlastpage = false;
498 $lastpageno=1;
500 // If an invalid nrows is supplied,
501 // we assume a default value of 10 rows per page
502 if (!isset($nrows) || $nrows <= 0) $nrows = 10;
504 $qryRecs = false; //count records for no offset
506 $qryRecs = _adodb_getcount($zthis,$sql,$inputarr,$secs2cache);
507 $lastpageno = (int) ceil($qryRecs / $nrows);
508 $zthis->_maxRecordCount = $qryRecs;
512 // ***** Here we check whether $page is the last page or
513 // whether we are trying to retrieve
514 // a page number greater than the last page number.
515 if ($page >= $lastpageno) {
516 $page = $lastpageno;
517 $atlastpage = true;
520 // If page number <= 1, then we are at the first page
521 if (empty($page) || $page <= 1) {
522 $page = 1;
523 $atfirstpage = true;
526 // We get the data we want
527 $offset = $nrows * ($page-1);
528 if ($secs2cache > 0)
529 $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
530 else
531 $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
534 // Before returning the RecordSet, we set the pagination properties we need
535 if ($rsreturn) {
536 $rsreturn->_maxRecordCount = $qryRecs;
537 $rsreturn->rowsPerPage = $nrows;
538 $rsreturn->AbsolutePage($page);
539 $rsreturn->AtFirstPage($atfirstpage);
540 $rsreturn->AtLastPage($atlastpage);
541 $rsreturn->LastPageNo($lastpageno);
543 return $rsreturn;
546 // Iván Oliva version
547 function _adodb_pageexecute_no_last_page(&$zthis, $sql, $nrows, $page, $inputarr=false, $secs2cache=0)
550 $atfirstpage = false;
551 $atlastpage = false;
553 if (!isset($page) || $page <= 1) { // If page number <= 1, then we are at the first page
554 $page = 1;
555 $atfirstpage = true;
557 if ($nrows <= 0) $nrows = 10; // If an invalid nrows is supplied, we assume a default value of 10 rows per page
559 // ***** Here we check whether $page is the last page or whether we are trying to retrieve a page number greater than
560 // the last page number.
561 $pagecounter = $page + 1;
562 $pagecounteroffset = ($pagecounter * $nrows) - $nrows;
563 if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
564 else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
565 if ($rstest) {
566 while ($rstest && $rstest->EOF && $pagecounter>0) {
567 $atlastpage = true;
568 $pagecounter--;
569 $pagecounteroffset = $nrows * ($pagecounter - 1);
570 $rstest->Close();
571 if ($secs2cache>0) $rstest = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $pagecounteroffset, $inputarr);
572 else $rstest = $zthis->SelectLimit($sql, $nrows, $pagecounteroffset, $inputarr, $secs2cache);
574 if ($rstest) $rstest->Close();
576 if ($atlastpage) { // If we are at the last page or beyond it, we are going to retrieve it
577 $page = $pagecounter;
578 if ($page == 1) $atfirstpage = true; // We have to do this again in case the last page is the same as the first
579 //... page, that is, the recordset has only 1 page.
582 // We get the data we want
583 $offset = $nrows * ($page-1);
584 if ($secs2cache > 0) $rsreturn = $zthis->CacheSelectLimit($secs2cache, $sql, $nrows, $offset, $inputarr);
585 else $rsreturn = $zthis->SelectLimit($sql, $nrows, $offset, $inputarr, $secs2cache);
587 // Before returning the RecordSet, we set the pagination properties we need
588 if ($rsreturn) {
589 $rsreturn->rowsPerPage = $nrows;
590 $rsreturn->AbsolutePage($page);
591 $rsreturn->AtFirstPage($atfirstpage);
592 $rsreturn->AtLastPage($atlastpage);
594 return $rsreturn;
597 function _adodb_getupdatesql(&$zthis,&$rs, $arrFields,$forceUpdate=false,$magicq=false,$force=2)
599 global $ADODB_QUOTE_FIELDNAMES;
601 if (!$rs) {
602 printf(ADODB_BAD_RS,'GetUpdateSQL');
603 return false;
606 $fieldUpdatedCount = 0;
607 $arrFields = _array_change_key_case($arrFields);
609 $hasnumeric = isset($rs->fields[0]);
610 $setFields = '';
612 // Loop through all of the fields in the recordset
613 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++) {
614 // Get the field from the recordset
615 $field = $rs->FetchField($i);
617 // If the recordset field is one
618 // of the fields passed in then process.
619 $upperfname = strtoupper($field->name);
620 if (adodb_key_exists($upperfname,$arrFields,$force)) {
622 // If the existing field value in the recordset
623 // is different from the value passed in then
624 // go ahead and append the field name and new value to
625 // the update query.
627 if ($hasnumeric) $val = $rs->fields[$i];
628 else if (isset($rs->fields[$upperfname])) $val = $rs->fields[$upperfname];
629 else if (isset($rs->fields[$field->name])) $val = $rs->fields[$field->name];
630 else if (isset($rs->fields[strtolower($upperfname)])) $val = $rs->fields[strtolower($upperfname)];
631 else $val = '';
634 if ($forceUpdate || strcmp($val, $arrFields[$upperfname])) {
635 // Set the counter for the number of fields that will be updated.
636 $fieldUpdatedCount++;
638 // Based on the datatype of the field
639 // Format the value properly for the database
640 $type = $rs->MetaType($field->type);
643 if ($type == 'null') {
644 $type = 'C';
647 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) {
648 switch ($ADODB_QUOTE_FIELDNAMES) {
649 case 'LOWER':
650 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break;
651 case 'NATIVE':
652 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break;
653 case 'UPPER':
654 default:
655 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break;
657 } else
658 $fnameq = $upperfname;
660 //********************************************************//
661 if (is_null($arrFields[$upperfname])
662 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
663 || $arrFields[$upperfname] === $zthis->null2null
666 switch ($force) {
668 //case 0:
669 // //Ignore empty values. This is allready handled in "adodb_key_exists" function.
670 //break;
672 case 1:
673 //Set null
674 $setFields .= $field->name . " = null, ";
675 break;
677 case 2:
678 //Set empty
679 $arrFields[$upperfname] = "";
680 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
681 break;
682 default:
683 case 3:
684 //Set the value that was given in array, so you can give both null and empty values
685 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
686 $setFields .= $field->name . " = null, ";
687 } else {
688 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,$arrFields, $magicq);
690 break;
692 //********************************************************//
693 } else {
694 //we do this so each driver can customize the sql for
695 //DB specific column types.
696 //Oracle needs BLOB types to be handled with a returning clause
697 //postgres has special needs as well
698 $setFields .= _adodb_column_sql($zthis, 'U', $type, $upperfname, $fnameq,
699 $arrFields, $magicq);
705 // If there were any modified fields then build the rest of the update query.
706 if ($fieldUpdatedCount > 0 || $forceUpdate) {
707 // Get the table name from the existing query.
708 if (!empty($rs->tableName)) $tableName = $rs->tableName;
709 else {
710 preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName);
711 $tableName = $tableName[1];
713 // Get the full where clause excluding the word "WHERE" from
714 // the existing query.
715 preg_match('/\sWHERE\s(.*)/is', $rs->sql, $whereClause);
717 $discard = false;
718 // not a good hack, improvements?
719 if ($whereClause) {
720 #var_dump($whereClause);
721 if (preg_match('/\s(ORDER\s.*)/is', $whereClause[1], $discard));
722 else if (preg_match('/\s(LIMIT\s.*)/is', $whereClause[1], $discard));
723 else if (preg_match('/\s(FOR UPDATE.*)/is', $whereClause[1], $discard));
724 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
725 } else
726 $whereClause = array(false,false);
728 if ($discard)
729 $whereClause[1] = substr($whereClause[1], 0, strlen($whereClause[1]) - strlen($discard[1]));
731 $sql = 'UPDATE '.$tableName.' SET '.substr($setFields, 0, -2);
732 if (strlen($whereClause[1]) > 0)
733 $sql .= ' WHERE '.$whereClause[1];
735 return $sql;
737 } else {
738 return false;
742 function adodb_key_exists($key, &$arr,$force=2)
744 if ($force<=0) {
745 // the following is the old behaviour where null or empty fields are ignored
746 return (!empty($arr[$key])) || (isset($arr[$key]) && strlen($arr[$key])>0);
749 if (isset($arr[$key])) return true;
750 ## null check below
751 if (ADODB_PHPVER >= 0x4010) return array_key_exists($key,$arr);
752 return false;
756 * There is a special case of this function for the oci8 driver.
757 * The proper way to handle an insert w/ a blob in oracle requires
758 * a returning clause with bind variables and a descriptor blob.
762 function _adodb_getinsertsql(&$zthis,&$rs,$arrFields,$magicq=false,$force=2)
764 static $cacheRS = false;
765 static $cacheSig = 0;
766 static $cacheCols;
767 global $ADODB_QUOTE_FIELDNAMES;
769 $tableName = '';
770 $values = '';
771 $fields = '';
772 $recordSet = null;
773 $arrFields = _array_change_key_case($arrFields);
774 $fieldInsertedCount = 0;
776 if (is_string($rs)) {
777 //ok we have a table name
778 //try and get the column info ourself.
779 $tableName = $rs;
781 //we need an object for the recordSet
782 //because we have to call MetaType.
783 //php can't do a $rsclass::MetaType()
784 $rsclass = $zthis->rsPrefix.$zthis->databaseType;
785 $recordSet = new $rsclass(-1,$zthis->fetchMode);
786 $recordSet->connection = $zthis;
788 if (is_string($cacheRS) && $cacheRS == $rs) {
789 $columns = $cacheCols;
790 } else {
791 $columns = $zthis->MetaColumns( $tableName );
792 $cacheRS = $tableName;
793 $cacheCols = $columns;
795 } else if (is_subclass_of($rs, 'adorecordset')) {
796 if (isset($rs->insertSig) && is_integer($cacheRS) && $cacheRS == $rs->insertSig) {
797 $columns = $cacheCols;
798 } else {
799 for ($i=0, $max=$rs->FieldCount(); $i < $max; $i++)
800 $columns[] = $rs->FetchField($i);
801 $cacheRS = $cacheSig;
802 $cacheCols = $columns;
803 $rs->insertSig = $cacheSig++;
805 $recordSet = $rs;
807 } else {
808 printf(ADODB_BAD_RS,'GetInsertSQL');
809 return false;
812 // Loop through all of the fields in the recordset
813 foreach( $columns as $field ) {
814 $upperfname = strtoupper($field->name);
815 if (adodb_key_exists($upperfname,$arrFields,$force)) {
816 $bad = false;
817 if ((strpos($upperfname,' ') !== false) || ($ADODB_QUOTE_FIELDNAMES)) {
818 switch ($ADODB_QUOTE_FIELDNAMES) {
819 case 'LOWER':
820 $fnameq = $zthis->nameQuote.strtolower($field->name).$zthis->nameQuote;break;
821 case 'NATIVE':
822 $fnameq = $zthis->nameQuote.$field->name.$zthis->nameQuote;break;
823 case 'UPPER':
824 default:
825 $fnameq = $zthis->nameQuote.$upperfname.$zthis->nameQuote;break;
827 } else
828 $fnameq = $upperfname;
830 $type = $recordSet->MetaType($field->type);
832 /********************************************************/
833 if (is_null($arrFields[$upperfname])
834 || (empty($arrFields[$upperfname]) && strlen($arrFields[$upperfname]) == 0)
835 || $arrFields[$upperfname] === $zthis->null2null
838 switch ($force) {
840 case 0: // we must always set null if missing
841 $bad = true;
842 break;
844 case 1:
845 $values .= "null, ";
846 break;
848 case 2:
849 //Set empty
850 $arrFields[$upperfname] = "";
851 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,$arrFields, $magicq);
852 break;
854 default:
855 case 3:
856 //Set the value that was given in array, so you can give both null and empty values
857 if (is_null($arrFields[$upperfname]) || $arrFields[$upperfname] === $zthis->null2null) {
858 $values .= "null, ";
859 } else {
860 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq, $arrFields, $magicq);
862 break;
863 } // switch
865 /*********************************************************/
866 } else {
867 //we do this so each driver can customize the sql for
868 //DB specific column types.
869 //Oracle needs BLOB types to be handled with a returning clause
870 //postgres has special needs as well
871 $values .= _adodb_column_sql($zthis, 'I', $type, $upperfname, $fnameq,
872 $arrFields, $magicq);
875 if ($bad) continue;
876 // Set the counter for the number of fields that will be inserted.
877 $fieldInsertedCount++;
880 // Get the name of the fields to insert
881 $fields .= $fnameq . ", ";
886 // If there were any inserted fields then build the rest of the insert query.
887 if ($fieldInsertedCount <= 0) return false;
889 // Get the table name from the existing query.
890 if (!$tableName) {
891 if (!empty($rs->tableName)) $tableName = $rs->tableName;
892 else if (preg_match("/FROM\s+".ADODB_TABLE_REGEX."/is", $rs->sql, $tableName))
893 $tableName = $tableName[1];
894 else
895 return false;
898 // Strip off the comma and space on the end of both the fields
899 // and their values.
900 $fields = substr($fields, 0, -2);
901 $values = substr($values, 0, -2);
903 // Append the fields and their values to the insert query.
904 return 'INSERT INTO '.$tableName.' ( '.$fields.' ) VALUES ( '.$values.' )';
909 * This private method is used to help construct
910 * the update/sql which is generated by GetInsertSQL and GetUpdateSQL.
911 * It handles the string construction of 1 column -> sql string based on
912 * the column type. We want to do 'safe' handling of BLOBs
914 * @param string the type of sql we are trying to create
915 * 'I' or 'U'.
916 * @param string column data type from the db::MetaType() method
917 * @param string the column name
918 * @param array the column value
920 * @return string
923 function _adodb_column_sql_oci8(&$zthis,$action, $type, $fname, $fnameq, $arrFields, $magicq)
925 $sql = '';
927 // Based on the datatype of the field
928 // Format the value properly for the database
929 switch($type) {
930 case 'B':
931 //in order to handle Blobs correctly, we need
932 //to do some magic for Oracle
934 //we need to create a new descriptor to handle
935 //this properly
936 if (!empty($zthis->hasReturningInto)) {
937 if ($action == 'I') {
938 $sql = 'empty_blob(), ';
939 } else {
940 $sql = $fnameq. '=empty_blob(), ';
942 //add the variable to the returning clause array
943 //so the user can build this later in
944 //case they want to add more to it
945 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
946 } else if (empty($arrFields[$fname])){
947 if ($action == 'I') {
948 $sql = 'empty_blob(), ';
949 } else {
950 $sql = $fnameq. '=empty_blob(), ';
952 } else {
953 //this is to maintain compatibility
954 //with older adodb versions.
955 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
957 break;
959 case "X":
960 //we need to do some more magic here for long variables
961 //to handle these correctly in oracle.
963 //create a safe bind var name
964 //to avoid conflicts w/ dupes.
965 if (!empty($zthis->hasReturningInto)) {
966 if ($action == 'I') {
967 $sql = ':xx'.$fname.'xx, ';
968 } else {
969 $sql = $fnameq.'=:xx'.$fname.'xx, ';
971 //add the variable to the returning clause array
972 //so the user can build this later in
973 //case they want to add more to it
974 $zthis->_returningArray[$fname] = ':xx'.$fname.'xx';
975 } else {
976 //this is to maintain compatibility
977 //with older adodb versions.
978 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
980 break;
982 default:
983 $sql = _adodb_column_sql($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq,false);
984 break;
987 return $sql;
990 function _adodb_column_sql(&$zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq, $recurse=true)
993 if ($recurse) {
994 switch($zthis->dataProvider) {
995 case 'postgres':
996 if ($type == 'L') $type = 'C';
997 break;
998 case 'oci8':
999 return _adodb_column_sql_oci8($zthis, $action, $type, $fname, $fnameq, $arrFields, $magicq);
1004 switch($type) {
1005 case "C":
1006 case "X":
1007 case 'B':
1008 $val = $zthis->qstr($arrFields[$fname],$magicq);
1009 break;
1011 case "D":
1012 $val = $zthis->DBDate($arrFields[$fname]);
1013 break;
1015 case "T":
1016 $val = $zthis->DBTimeStamp($arrFields[$fname]);
1017 break;
1019 case "N":
1020 $val = $arrFields[$fname];
1021 if (!is_numeric($val)) $val = str_replace(',', '.', (float)$val);
1022 break;
1024 case "I":
1025 case "R":
1026 $val = $arrFields[$fname];
1027 if (!is_numeric($val)) $val = (integer) $val;
1028 break;
1030 default:
1031 $val = str_replace(array("'"," ","("),"",$arrFields[$fname]); // basic sql injection defence
1032 if (empty($val)) $val = '0';
1033 break;
1036 if ($action == 'I') return $val . ", ";
1039 return $fnameq . "=" . $val . ", ";
1045 function _adodb_debug_execute(&$zthis, $sql, $inputarr)
1047 $ss = '';
1048 if ($inputarr) {
1049 foreach($inputarr as $kk=>$vv) {
1050 if (is_string($vv) && strlen($vv)>64) $vv = substr($vv,0,64).'...';
1051 if (is_null($vv)) $ss .= "($kk=>null) ";
1052 else $ss .= "($kk=>'$vv') ";
1054 $ss = "[ $ss ]";
1056 $sqlTxt = is_array($sql) ? $sql[0] : $sql;
1057 /*str_replace(', ','##1#__^LF',is_array($sql) ? $sql[0] : $sql);
1058 $sqlTxt = str_replace(',',', ',$sqlTxt);
1059 $sqlTxt = str_replace('##1#__^LF', ', ' ,$sqlTxt);
1061 // check if running from browser or command-line
1062 $inBrowser = isset($_SERVER['HTTP_USER_AGENT']);
1064 $dbt = $zthis->databaseType;
1065 if (isset($zthis->dsnType)) $dbt .= '-'.$zthis->dsnType;
1066 if ($inBrowser) {
1067 if ($ss) {
1068 $ss = '<code>'.htmlspecialchars($ss).'</code>';
1070 if ($zthis->debug === -1)
1071 ADOConnection::outp( "<br>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<br>\n",false);
1072 else if ($zthis->debug !== -99)
1073 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
1074 } else {
1075 $ss = "\n ".$ss;
1076 if ($zthis->debug !== -99)
1077 ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt." $ss\n-----<hr>\n",false);
1080 $qID = $zthis->_query($sql,$inputarr);
1083 Alexios Fakios notes that ErrorMsg() must be called before ErrorNo() for mssql
1084 because ErrorNo() calls Execute('SELECT @ERROR'), causing recursion
1086 if ($zthis->databaseType == 'mssql') {
1087 // ErrorNo is a slow function call in mssql, and not reliable in PHP 4.0.6
1089 if($emsg = $zthis->ErrorMsg()) {
1090 if ($err = $zthis->ErrorNo()) {
1091 if ($zthis->debug === -99)
1092 ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
1094 ADOConnection::outp($err.': '.$emsg);
1097 } else if (!$qID) {
1099 if ($zthis->debug === -99)
1100 if ($inBrowser) ADOConnection::outp( "<hr>\n($dbt): ".htmlspecialchars($sqlTxt)." &nbsp; $ss\n<hr>\n",false);
1101 else ADOConnection::outp("-----<hr>\n($dbt): ".$sqlTxt."$ss\n-----<hr>\n",false);
1103 ADOConnection::outp($zthis->ErrorNo() .': '. $zthis->ErrorMsg());
1106 if ($zthis->debug === 99) _adodb_backtrace(true,9999,2);
1107 return $qID;
1110 # pretty print the debug_backtrace function
1111 function _adodb_backtrace($printOrArr=true,$levels=9999,$skippy=0,$ishtml=null)
1113 if (!function_exists('debug_backtrace')) return '';
1115 if ($ishtml === null) $html = (isset($_SERVER['HTTP_USER_AGENT']));
1116 else $html = $ishtml;
1118 $fmt = ($html) ? "</font><font color=#808080 size=-1> %% line %4d, file: <a href=\"file:/%s\">%s</a></font>" : "%% line %4d, file: %s";
1120 $MAXSTRLEN = 128;
1122 $s = ($html) ? '<pre align=left>' : '';
1124 if (is_array($printOrArr)) $traceArr = $printOrArr;
1125 else $traceArr = debug_backtrace();
1126 array_shift($traceArr);
1127 array_shift($traceArr);
1128 $tabs = sizeof($traceArr)-2;
1130 foreach ($traceArr as $arr) {
1131 if ($skippy) {$skippy -= 1; continue;}
1132 $levels -= 1;
1133 if ($levels < 0) break;
1135 $args = array();
1136 for ($i=0; $i < $tabs; $i++) $s .= ($html) ? ' &nbsp; ' : "\t";
1137 $tabs -= 1;
1138 if ($html) $s .= '<font face="Courier New,Courier">';
1139 if (isset($arr['class'])) $s .= $arr['class'].'.';
1140 if (isset($arr['args']))
1141 foreach($arr['args'] as $v) {
1142 if (is_null($v)) $args[] = 'null';
1143 else if (is_array($v)) $args[] = 'Array['.sizeof($v).']';
1144 else if (is_object($v)) $args[] = 'Object:'.get_class($v);
1145 else if (is_bool($v)) $args[] = $v ? 'true' : 'false';
1146 else {
1147 $v = (string) @$v;
1148 $str = htmlspecialchars(str_replace(array("\r","\n"),' ',substr($v,0,$MAXSTRLEN)));
1149 if (strlen($v) > $MAXSTRLEN) $str .= '...';
1150 $args[] = $str;
1153 $s .= $arr['function'].'('.implode(', ',$args).')';
1156 $s .= @sprintf($fmt, $arr['line'],$arr['file'],basename($arr['file']));
1158 $s .= "\n";
1160 if ($html) $s .= '</pre>';
1161 if ($printOrArr) print $s;
1163 return $s;
1166 function _adodb_find_from($sql)
1169 $sql = str_replace(array("\n","\r"), ' ', $sql);
1170 $charCount = strlen($sql);
1172 $inString = false;
1173 $quote = '';
1174 $parentheseCount = 0;
1175 $prevChars = '';
1176 $nextChars = '';
1179 for($i = 0; $i < $charCount; $i++) {
1181 $char = substr($sql,$i,1);
1182 $prevChars = substr($sql,0,$i);
1183 $nextChars = substr($sql,$i+1);
1185 if((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === false) {
1186 $quote = $char;
1187 $inString = true;
1190 elseif((($char == "'" || $char == '"' || $char == '`') && substr($prevChars,-1,1) != '\\') && $inString === true && $quote == $char) {
1191 $quote = "";
1192 $inString = false;
1195 elseif($char == "(" && $inString === false)
1196 $parentheseCount++;
1198 elseif($char == ")" && $inString === false && $parentheseCount > 0)
1199 $parentheseCount--;
1201 elseif($parentheseCount <= 0 && $inString === false && $char == " " && strtoupper(substr($prevChars,-5,5)) == " FROM")
1202 return $i;