Verzeichnisstruktur phpBB-3.1.0
- Veröffentlicht
- 27.10.2014
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
oracle.php
001 <?php
002 /**
003 *
004 * This file is part of the phpBB Forum Software package.
005 *
006 * @copyright (c) phpBB Limited <https://www.phpbb.com>
007 * @license GNU General Public License, version 2 (GPL-2.0)
008 *
009 * For full copyright and license information, please see
010 * the docs/CREDITS.txt file.
011 *
012 */
013
014 namespace phpbb\db\driver;
015
016 /**
017 * Oracle Database Abstraction Layer
018 */
019 class oracle extends \phpbb\db\driver\driver
020 {
021 var $last_query_text = '';
022 var $connect_error = '';
023
024 /**
025 * {@inheritDoc}
026 */
027 function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false)
028 {
029 $this->persistency = $persistency;
030 $this->user = $sqluser;
031 $this->server = $sqlserver . (($port) ? ':' . $port : '');
032 $this->dbname = $database;
033
034 $connect = $database;
035
036 // support for "easy connect naming"
037 if ($sqlserver !== '' && $sqlserver !== '/')
038 {
039 if (substr($sqlserver, -1, 1) == '/')
040 {
041 $sqlserver == substr($sqlserver, 0, -1);
042 }
043 $connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database;
044 }
045
046 if ($new_link)
047 {
048 if (!function_exists('ocinlogon'))
049 {
050 $this->connect_error = 'ocinlogon function does not exist, is oci extension installed?';
051 return $this->sql_error('');
052 }
053 $this->db_connect_id = @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8');
054 }
055 else if ($this->persistency)
056 {
057 if (!function_exists('ociplogon'))
058 {
059 $this->connect_error = 'ociplogon function does not exist, is oci extension installed?';
060 return $this->sql_error('');
061 }
062 $this->db_connect_id = @ociplogon($this->user, $sqlpassword, $connect, 'UTF8');
063 }
064 else
065 {
066 if (!function_exists('ocilogon'))
067 {
068 $this->connect_error = 'ocilogon function does not exist, is oci extension installed?';
069 return $this->sql_error('');
070 }
071 $this->db_connect_id = @ocilogon($this->user, $sqlpassword, $connect, 'UTF8');
072 }
073
074 return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error('');
075 }
076
077 /**
078 * {@inheritDoc}
079 */
080 function sql_server_info($raw = false, $use_cache = true)
081 {
082 /**
083 * force $use_cache false. I didn't research why the caching code below is commented out
084 * but I assume its because the Oracle extension provides a direct method to access it
085 * without a query.
086 */
087
088 $use_cache = false;
089 /*
090 global $cache;
091
092 if (empty($cache) || ($this->sql_server_version = $cache->get('oracle_version')) === false)
093 {
094 $result = @ociparse($this->db_connect_id, 'SELECT * FROM v$version WHERE banner LIKE \'Oracle%\'');
095 @ociexecute($result, OCI_DEFAULT);
096 @ocicommit($this->db_connect_id);
097
098 $row = array();
099 @ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS);
100 @ocifreestatement($result);
101 $this->sql_server_version = trim($row['BANNER']);
102
103 $cache->put('oracle_version', $this->sql_server_version);
104 }
105 */
106 $this->sql_server_version = @ociserverversion($this->db_connect_id);
107
108 return $this->sql_server_version;
109 }
110
111 /**
112 * SQL Transaction
113 * @access private
114 */
115 function _sql_transaction($status = 'begin')
116 {
117 switch ($status)
118 {
119 case 'begin':
120 return true;
121 break;
122
123 case 'commit':
124 return @ocicommit($this->db_connect_id);
125 break;
126
127 case 'rollback':
128 return @ocirollback($this->db_connect_id);
129 break;
130 }
131
132 return true;
133 }
134
135 /**
136 * Oracle specific code to handle the fact that it does not compare columns properly
137 * @access private
138 */
139 function _rewrite_col_compare($args)
140 {
141 if (sizeof($args) == 4)
142 {
143 if ($args[2] == '=')
144 {
145 return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))';
146 }
147 else if ($args[2] == '<>')
148 {
149 // really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
150 return '(' . $args[0] . ' OR ((' . $args[1] . ' is NULL AND ' . $args[3] . ' is NOT NULL) OR (' . $args[1] . ' is NOT NULL AND ' . $args[3] . ' is NULL)))';
151 }
152 }
153 else
154 {
155 return $this->_rewrite_where($args[0]);
156 }
157 }
158
159 /**
160 * Oracle specific code to handle it's lack of sanity
161 * @access private
162 */
163 function _rewrite_where($where_clause)
164 {
165 preg_match_all('/\s*(AND|OR)?\s*([\w_.()]++)\s*(?:(=|<[=>]?|>=?|LIKE)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.()]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER);
166 $out = '';
167 foreach ($result as $val)
168 {
169 if (!isset($val[5]))
170 {
171 if ($val[4] !== "''")
172 {
173 $out .= $val[0];
174 }
175 else
176 {
177 $out .= ' ' . $val[1] . ' ' . $val[2];
178 if ($val[3] == '=')
179 {
180 $out .= ' is NULL';
181 }
182 else if ($val[3] == '<>')
183 {
184 $out .= ' is NOT NULL';
185 }
186 }
187 }
188 else
189 {
190 $in_clause = array();
191 $sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1);
192 $extra = false;
193 preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER);
194 $i = 0;
195 foreach ($sub_vals[0] as $sub_val)
196 {
197 // two things:
198 // 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
199 // 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
200 if ($sub_val !== "''")
201 {
202 $in_clause[(int) $i++/1000][] = $sub_val;
203 }
204 else
205 {
206 $extra = true;
207 }
208 }
209 if (!$extra && $i < 1000)
210 {
211 $out .= $val[0];
212 }
213 else
214 {
215 $out .= ' ' . $val[1] . '(';
216 $in_array = array();
217
218 // constuct each IN() clause
219 foreach ($in_clause as $in_values)
220 {
221 $in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')';
222 }
223
224 // Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
225 $out .= implode(' OR ', $in_array);
226
227 // handle the empty string case
228 if ($extra)
229 {
230 $out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL';
231 }
232 $out .= ')';
233
234 unset($in_array, $in_clause);
235 }
236 }
237 }
238
239 return $out;
240 }
241
242 /**
243 * {@inheritDoc}
244 */
245 function sql_query($query = '', $cache_ttl = 0)
246 {
247 if ($query != '')
248 {
249 global $cache;
250
251 // EXPLAIN only in extra debug mode
252 if (defined('DEBUG'))
253 {
254 $this->sql_report('start', $query);
255 }
256 else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
257 {
258 $this->curtime = microtime(true);
259 }
260
261 $this->last_query_text = $query;
262 $this->query_result = ($cache && $cache_ttl) ? $cache->sql_load($query) : false;
263 $this->sql_add_num_queries($this->query_result);
264
265 if ($this->query_result === false)
266 {
267 $in_transaction = false;
268 if (!$this->transaction)
269 {
270 $this->sql_transaction('begin');
271 }
272 else
273 {
274 $in_transaction = true;
275 }
276
277 $array = array();
278
279 // We overcome Oracle's 4000 char limit by binding vars
280 if (strlen($query) > 4000)
281 {
282 if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/sU', $query, $regs))
283 {
284 if (strlen($regs[3]) > 4000)
285 {
286 $cols = explode(', ', $regs[2]);
287
288 preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER);
289
290 /* The code inside this comment block breaks clob handling, but does allow the
291 database restore script to work. If you want to allow no posts longer than 4KB
292 and/or need the db restore script, uncomment this.
293
294
295 if (sizeof($cols) !== sizeof($vals))
296 {
297 // Try to replace some common data we know is from our restore script or from other sources
298 $regs[3] = str_replace("'||chr(47)||'", '/', $regs[3]);
299 $_vals = explode(', ', $regs[3]);
300
301 $vals = array();
302 $is_in_val = false;
303 $i = 0;
304 $string = '';
305
306 foreach ($_vals as $value)
307 {
308 if (strpos($value, "'") === false && !$is_in_val)
309 {
310 $vals[$i++] = $value;
311 continue;
312 }
313
314 if (substr($value, -1) === "'")
315 {
316 $vals[$i] = $string . (($is_in_val) ? ', ' : '') . $value;
317 $string = '';
318 $is_in_val = false;
319
320 if ($vals[$i][0] !== "'")
321 {
322 $vals[$i] = "''" . $vals[$i];
323 }
324 $i++;
325 continue;
326 }
327 else
328 {
329 $string .= (($is_in_val) ? ', ' : '') . $value;
330 $is_in_val = true;
331 }
332 }
333
334 if ($string)
335 {
336 // New value if cols != value
337 $vals[(sizeof($cols) !== sizeof($vals)) ? $i : $i - 1] .= $string;
338 }
339
340 $vals = array(0 => $vals);
341 }
342 */
343
344 $inserts = $vals[0];
345 unset($vals);
346
347 foreach ($inserts as $key => $value)
348 {
349 if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2
350 {
351 $inserts[$key] = ':' . strtoupper($cols[$key]);
352 $array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1));
353 }
354 }
355
356 $query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')';
357 }
358 }
359 else if (preg_match_all('/^(UPDATE [\\w_]++\\s+SET )([\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+)(?:,\\s*[\\w_]++\\s*=\\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]+))*+)\\s+(WHERE.*)$/s', $query, $data, PREG_SET_ORDER))
360 {
361 if (strlen($data[0][2]) > 4000)
362 {
363 $update = $data[0][1];
364 $where = $data[0][3];
365 preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER);
366 unset($data);
367
368 $cols = array();
369 foreach ($temp as $value)
370 {
371 if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2
372 {
373 $cols[] = $value[1] . '=:' . strtoupper($value[1]);
374 $array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1));
375 }
376 else
377 {
378 $cols[] = $value[1] . '=' . $value[2];
379 }
380 }
381
382 $query = $update . implode(', ', $cols) . ' ' . $where;
383 unset($cols);
384 }
385 }
386 }
387
388 switch (substr($query, 0, 6))
389 {
390 case 'DELETE':
391 if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs))
392 {
393 $query = $regs[1] . $this->_rewrite_where($regs[2]);
394 unset($regs);
395 }
396 break;
397
398 case 'UPDATE':
399 if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs))
400 {
401 $query = $regs[1] . $this->_rewrite_where($regs[2]);
402 unset($regs);
403 }
404 break;
405
406 case 'SELECT':
407 $query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query);
408 break;
409 }
410
411 $this->query_result = @ociparse($this->db_connect_id, $query);
412
413 foreach ($array as $key => $value)
414 {
415 @ocibindbyname($this->query_result, $key, $array[$key], -1);
416 }
417
418 $success = @ociexecute($this->query_result, OCI_DEFAULT);
419
420 if (!$success)
421 {
422 $this->sql_error($query);
423 $this->query_result = false;
424 }
425 else
426 {
427 if (!$in_transaction)
428 {
429 $this->sql_transaction('commit');
430 }
431 }
432
433 if (defined('DEBUG'))
434 {
435 $this->sql_report('stop', $query);
436 }
437 else if (defined('PHPBB_DISPLAY_LOAD_TIME'))
438 {
439 $this->sql_time += microtime(true) - $this->curtime;
440 }
441
442 if ($cache && $cache_ttl)
443 {
444 $this->open_queries[(int) $this->query_result] = $this->query_result;
445 $this->query_result = $cache->sql_save($this, $query, $this->query_result, $cache_ttl);
446 }
447 else if (strpos($query, 'SELECT') === 0 && $this->query_result)
448 {
449 $this->open_queries[(int) $this->query_result] = $this->query_result;
450 }
451 }
452 else if (defined('DEBUG'))
453 {
454 $this->sql_report('fromcache', $query);
455 }
456 }
457 else
458 {
459 return false;
460 }
461
462 return $this->query_result;
463 }
464
465 /**
466 * Build LIMIT query
467 */
468 function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
469 {
470 $this->query_result = false;
471
472 $query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset;
473
474 return $this->sql_query($query, $cache_ttl);
475 }
476
477 /**
478 * {@inheritDoc}
479 */
480 function sql_affectedrows()
481 {
482 return ($this->query_result) ? @ocirowcount($this->query_result) : false;
483 }
484
485 /**
486 * {@inheritDoc}
487 */
488 function sql_fetchrow($query_id = false)
489 {
490 global $cache;
491
492 if ($query_id === false)
493 {
494 $query_id = $this->query_result;
495 }
496
497 if ($cache && $cache->sql_exists($query_id))
498 {
499 return $cache->sql_fetchrow($query_id);
500 }
501
502 if ($query_id !== false)
503 {
504 $row = array();
505 $result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS);
506
507 if (!$result || !$row)
508 {
509 return false;
510 }
511
512 $result_row = array();
513 foreach ($row as $key => $value)
514 {
515 // Oracle treats empty strings as null
516 if (is_null($value))
517 {
518 $value = '';
519 }
520
521 // OCI->CLOB?
522 if (is_object($value))
523 {
524 $value = $value->load();
525 }
526
527 $result_row[strtolower($key)] = $value;
528 }
529
530 return $result_row;
531 }
532
533 return false;
534 }
535
536 /**
537 * {@inheritDoc}
538 */
539 function sql_rowseek($rownum, &$query_id)
540 {
541 global $cache;
542
543 if ($query_id === false)
544 {
545 $query_id = $this->query_result;
546 }
547
548 if ($cache && $cache->sql_exists($query_id))
549 {
550 return $cache->sql_rowseek($rownum, $query_id);
551 }
552
553 if ($query_id === false)
554 {
555 return false;
556 }
557
558 // Reset internal pointer
559 @ociexecute($query_id, OCI_DEFAULT);
560
561 // We do not fetch the row for rownum == 0 because then the next resultset would be the second row
562 for ($i = 0; $i < $rownum; $i++)
563 {
564 if (!$this->sql_fetchrow($query_id))
565 {
566 return false;
567 }
568 }
569
570 return true;
571 }
572
573 /**
574 * {@inheritDoc}
575 */
576 function sql_nextid()
577 {
578 $query_id = $this->query_result;
579
580 if ($query_id !== false && $this->last_query_text != '')
581 {
582 if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename))
583 {
584 $query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL';
585 $stmt = @ociparse($this->db_connect_id, $query);
586 @ociexecute($stmt, OCI_DEFAULT);
587
588 $temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS);
589 @ocifreestatement($stmt);
590
591 if ($temp_result)
592 {
593 return $temp_array['CURRVAL'];
594 }
595 else
596 {
597 return false;
598 }
599 }
600 }
601
602 return false;
603 }
604
605 /**
606 * {@inheritDoc}
607 */
608 function sql_freeresult($query_id = false)
609 {
610 global $cache;
611
612 if ($query_id === false)
613 {
614 $query_id = $this->query_result;
615 }
616
617 if ($cache && !is_object($query_id) && $cache->sql_exists($query_id))
618 {
619 return $cache->sql_freeresult($query_id);
620 }
621
622 if (isset($this->open_queries[(int) $query_id]))
623 {
624 unset($this->open_queries[(int) $query_id]);
625 return @ocifreestatement($query_id);
626 }
627
628 return false;
629 }
630
631 /**
632 * {@inheritDoc}
633 */
634 function sql_escape($msg)
635 {
636 return str_replace(array("'", "\0"), array("''", ''), $msg);
637 }
638
639 /**
640 * Build LIKE expression
641 * @access private
642 */
643 function _sql_like_expression($expression)
644 {
645 return $expression . " ESCAPE '\\'";
646 }
647
648 /**
649 * Build NOT LIKE expression
650 * @access private
651 */
652 function _sql_not_like_expression($expression)
653 {
654 return $expression . " ESCAPE '\\'";
655 }
656
657 function _sql_custom_build($stage, $data)
658 {
659 return $data;
660 }
661
662 function _sql_bit_and($column_name, $bit, $compare = '')
663 {
664 return 'BITAND(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
665 }
666
667 function _sql_bit_or($column_name, $bit, $compare = '')
668 {
669 return 'BITOR(' . $column_name . ', ' . (1 << $bit) . ')' . (($compare) ? ' ' . $compare : '');
670 }
671
672 /**
673 * return sql error array
674 * @access private
675 */
676 function _sql_error()
677 {
678 if (function_exists('ocierror'))
679 {
680 $error = @ocierror();
681 $error = (!$error) ? @ocierror($this->query_result) : $error;
682 $error = (!$error) ? @ocierror($this->db_connect_id) : $error;
683
684 if ($error)
685 {
686 $this->last_error_result = $error;
687 }
688 else
689 {
690 $error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array();
691 }
692 }
693 else
694 {
695 $error = array(
696 'message' => $this->connect_error,
697 'code' => '',
698 );
699 }
700
701 return $error;
702 }
703
704 /**
705 * Close sql connection
706 * @access private
707 */
708 function _sql_close()
709 {
710 return @ocilogoff($this->db_connect_id);
711 }
712
713 /**
714 * Build db-specific report
715 * @access private
716 */
717 function _sql_report($mode, $query = '')
718 {
719 switch ($mode)
720 {
721 case 'start':
722
723 $html_table = false;
724
725 // Grab a plan table, any will do
726 $sql = "SELECT table_name
727 FROM USER_TABLES
728 WHERE table_name LIKE '%PLAN_TABLE%'";
729 $stmt = ociparse($this->db_connect_id, $sql);
730 ociexecute($stmt);
731 $result = array();
732
733 if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS))
734 {
735 $table = $result['TABLE_NAME'];
736
737 // This is the statement_id that will allow us to track the plan
738 $statement_id = substr(md5($query), 0, 30);
739
740 // Remove any stale plans
741 $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
742 ociexecute($stmt2);
743 ocifreestatement($stmt2);
744
745 // Explain the plan
746 $sql = "EXPLAIN PLAN
747 SET STATEMENT_ID = '$statement_id'
748 FOR $query";
749 $stmt2 = ociparse($this->db_connect_id, $sql);
750 ociexecute($stmt2);
751 ocifreestatement($stmt2);
752
753 // Get the data from the plan
754 $sql = "SELECT operation, options, object_name, object_type, cardinality, cost
755 FROM plan_table
756 START WITH id = 0 AND statement_id = '$statement_id'
757 CONNECT BY PRIOR id = parent_id
758 AND statement_id = '$statement_id'";
759 $stmt2 = ociparse($this->db_connect_id, $sql);
760 ociexecute($stmt2);
761
762 $row = array();
763 while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS))
764 {
765 $html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
766 }
767
768 ocifreestatement($stmt2);
769
770 // Remove the plan we just made, we delete them on request anyway
771 $stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'");
772 ociexecute($stmt2);
773 ocifreestatement($stmt2);
774 }
775
776 ocifreestatement($stmt);
777
778 if ($html_table)
779 {
780 $this->html_hold .= '</table>';
781 }
782
783 break;
784
785 case 'fromcache':
786 $endtime = explode(' ', microtime());
787 $endtime = $endtime[0] + $endtime[1];
788
789 $result = @ociparse($this->db_connect_id, $query);
790 $success = @ociexecute($result, OCI_DEFAULT);
791 $row = array();
792
793 while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS))
794 {
795 // Take the time spent on parsing rows into account
796 }
797 @ocifreestatement($result);
798
799 $splittime = explode(' ', microtime());
800 $splittime = $splittime[0] + $splittime[1];
801
802 $this->sql_report('record_fromcache', $query, $endtime, $splittime);
803
804 break;
805 }
806 }
807 }
808