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