443
by dcoles
Added Forum application along with unmodifed version of phpBB3 "Olympus" 3.0.0 |
1 |
<?php
|
2 |
/**
|
|
3 |
*
|
|
4 |
* @package dbal
|
|
5 |
* @version $Id: oracle.php,v 1.50 2007/10/05 14:36:32 acydburn Exp $
|
|
6 |
* @copyright (c) 2005 phpBB Group
|
|
7 |
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
|
|
8 |
*
|
|
9 |
*/
|
|
10 |
||
11 |
/**
|
|
12 |
* @ignore
|
|
13 |
*/
|
|
14 |
if (!defined('IN_PHPBB')) |
|
15 |
{
|
|
16 |
exit; |
|
17 |
}
|
|
18 |
||
19 |
include_once($phpbb_root_path . 'includes/db/dbal.' . $phpEx); |
|
20 |
||
21 |
/**
|
|
22 |
* Oracle Database Abstraction Layer
|
|
23 |
* @package dbal
|
|
24 |
*/
|
|
25 |
class dbal_oracle extends dbal |
|
26 |
{
|
|
27 |
var $last_query_text = ''; |
|
28 |
||
29 |
/**
|
|
30 |
* Connect to server
|
|
31 |
*/
|
|
32 |
function sql_connect($sqlserver, $sqluser, $sqlpassword, $database, $port = false, $persistency = false, $new_link = false) |
|
33 |
{
|
|
34 |
$this->persistency = $persistency; |
|
35 |
$this->user = $sqluser; |
|
36 |
$this->server = $sqlserver . (($port) ? ':' . $port : ''); |
|
37 |
$this->dbname = $database; |
|
38 |
||
39 |
$connect = $database; |
|
40 |
||
41 |
// support for "easy connect naming"
|
|
42 |
if ($sqlserver !== '' && $sqlserver !== '/') |
|
43 |
{
|
|
44 |
if (substr($sqlserver, -1, 1) == '/') |
|
45 |
{
|
|
46 |
$sqlserver == substr($sqlserver, 0, -1); |
|
47 |
}
|
|
48 |
$connect = $sqlserver . (($port) ? ':' . $port : '') . '/' . $database; |
|
49 |
}
|
|
50 |
||
51 |
$this->db_connect_id = ($new_link) ? @ocinlogon($this->user, $sqlpassword, $connect, 'UTF8') : (($this->persistency) ? @ociplogon($this->user, $sqlpassword, $connect, 'UTF8') : @ocilogon($this->user, $sqlpassword, $connect, 'UTF8')); |
|
52 |
||
53 |
return ($this->db_connect_id) ? $this->db_connect_id : $this->sql_error(''); |
|
54 |
}
|
|
55 |
||
56 |
/**
|
|
57 |
* Version information about used database
|
|
58 |
*/
|
|
59 |
function sql_server_info() |
|
60 |
{
|
|
61 |
return @ociserverversion($this->db_connect_id); |
|
62 |
}
|
|
63 |
||
64 |
/**
|
|
65 |
* SQL Transaction
|
|
66 |
* @access private
|
|
67 |
*/
|
|
68 |
function _sql_transaction($status = 'begin') |
|
69 |
{
|
|
70 |
switch ($status) |
|
71 |
{
|
|
72 |
case 'begin': |
|
73 |
return true; |
|
74 |
break; |
|
75 |
||
76 |
case 'commit': |
|
77 |
return @ocicommit($this->db_connect_id); |
|
78 |
break; |
|
79 |
||
80 |
case 'rollback': |
|
81 |
return @ocirollback($this->db_connect_id); |
|
82 |
break; |
|
83 |
}
|
|
84 |
||
85 |
return true; |
|
86 |
}
|
|
87 |
||
88 |
/**
|
|
89 |
* Oracle specific code to handle the fact that it does not compare columns properly
|
|
90 |
* @access private
|
|
91 |
*/
|
|
92 |
function _rewrite_col_compare($args) |
|
93 |
{
|
|
94 |
if (sizeof($args) == 4) |
|
95 |
{
|
|
96 |
if ($args[2] == '=') |
|
97 |
{
|
|
98 |
return '(' . $args[0] . ' OR (' . $args[1] . ' is NULL AND ' . $args[3] . ' is NULL))'; |
|
99 |
}
|
|
100 |
else if ($args[2] == '<>') |
|
101 |
{
|
|
102 |
// really just a fancy way of saying foo <> bar or (foo is NULL XOR bar is NULL) but SQL has no XOR :P
|
|
103 |
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)))'; |
|
104 |
}
|
|
105 |
}
|
|
106 |
else
|
|
107 |
{
|
|
108 |
return $this->_rewrite_where($args[0]); |
|
109 |
}
|
|
110 |
}
|
|
111 |
||
112 |
/**
|
|
113 |
* Oracle specific code to handle it's lack of sanity
|
|
114 |
* @access private
|
|
115 |
*/
|
|
116 |
function _rewrite_where($where_clause) |
|
117 |
{
|
|
118 |
preg_match_all('/\s*(AND|OR)?\s*([\w_.]++)\s*(?:(=|<[=>]?|>=?)\s*((?>\'(?>[^\']++|\'\')*+\'|[\d-.]+))|((NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))/', $where_clause, $result, PREG_SET_ORDER); |
|
119 |
$out = ''; |
|
120 |
foreach ($result as $val) |
|
121 |
{
|
|
122 |
if (!isset($val[5])) |
|
123 |
{
|
|
124 |
if ($val[4] !== "''") |
|
125 |
{
|
|
126 |
$out .= $val[0]; |
|
127 |
}
|
|
128 |
else
|
|
129 |
{
|
|
130 |
$out .= ' ' . $val[1] . ' ' . $val[2]; |
|
131 |
if ($val[3] == '=') |
|
132 |
{
|
|
133 |
$out .= ' is NULL'; |
|
134 |
}
|
|
135 |
else if ($val[3] == '<>') |
|
136 |
{
|
|
137 |
$out .= ' is NOT NULL'; |
|
138 |
}
|
|
139 |
}
|
|
140 |
}
|
|
141 |
else
|
|
142 |
{
|
|
143 |
$in_clause = array(); |
|
144 |
$sub_exp = substr($val[5], strpos($val[5], '(') + 1, -1); |
|
145 |
$extra = false; |
|
146 |
preg_match_all('/\'(?>[^\']++|\'\')*+\'|[\d-.]++/', $sub_exp, $sub_vals, PREG_PATTERN_ORDER); |
|
147 |
$i = 0; |
|
148 |
foreach ($sub_vals[0] as $sub_val) |
|
149 |
{
|
|
150 |
// two things:
|
|
151 |
// 1) This determines if an empty string was in the IN clausing, making us turn it into a NULL comparison
|
|
152 |
// 2) This fixes the 1000 list limit that Oracle has (ORA-01795)
|
|
153 |
if ($sub_val !== "''") |
|
154 |
{
|
|
155 |
$in_clause[(int) $i++/1000][] = $sub_val; |
|
156 |
}
|
|
157 |
else
|
|
158 |
{
|
|
159 |
$extra = true; |
|
160 |
}
|
|
161 |
}
|
|
162 |
if (!$extra && $i < 1000) |
|
163 |
{
|
|
164 |
$out .= $val[0]; |
|
165 |
}
|
|
166 |
else
|
|
167 |
{
|
|
168 |
$out .= ' ' . $val[1] . '('; |
|
169 |
$in_array = array(); |
|
170 |
||
171 |
// constuct each IN() clause
|
|
172 |
foreach ($in_clause as $in_values) |
|
173 |
{
|
|
174 |
$in_array[] = $val[2] . ' ' . (isset($val[6]) ? $val[6] : '') . 'IN(' . implode(', ', $in_values) . ')'; |
|
175 |
}
|
|
176 |
||
177 |
// Join the IN() clauses against a few ORs (IN is just a nicer OR anyway)
|
|
178 |
$out .= implode(' OR ', $in_array); |
|
179 |
||
180 |
// handle the empty string case
|
|
181 |
if ($extra) |
|
182 |
{
|
|
183 |
$out .= ' OR ' . $val[2] . ' is ' . (isset($val[6]) ? $val[6] : '') . 'NULL'; |
|
184 |
}
|
|
185 |
$out .= ')'; |
|
186 |
||
187 |
unset($in_array, $in_clause); |
|
188 |
}
|
|
189 |
}
|
|
190 |
}
|
|
191 |
||
192 |
return $out; |
|
193 |
}
|
|
194 |
||
195 |
/**
|
|
196 |
* Base query method
|
|
197 |
*
|
|
198 |
* @param string $query Contains the SQL query which shall be executed
|
|
199 |
* @param int $cache_ttl Either 0 to avoid caching or the time in seconds which the result shall be kept in cache
|
|
200 |
* @return mixed When casted to bool the returned value returns true on success and false on failure
|
|
201 |
*
|
|
202 |
* @access public
|
|
203 |
*/
|
|
204 |
function sql_query($query = '', $cache_ttl = 0) |
|
205 |
{
|
|
206 |
if ($query != '') |
|
207 |
{
|
|
208 |
global $cache; |
|
209 |
||
210 |
// EXPLAIN only in extra debug mode
|
|
211 |
if (defined('DEBUG_EXTRA')) |
|
212 |
{
|
|
213 |
$this->sql_report('start', $query); |
|
214 |
}
|
|
215 |
||
216 |
$this->last_query_text = $query; |
|
217 |
$this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query) : false; |
|
218 |
$this->sql_add_num_queries($this->query_result); |
|
219 |
||
220 |
if ($this->query_result === false) |
|
221 |
{
|
|
222 |
$in_transaction = false; |
|
223 |
if (!$this->transaction) |
|
224 |
{
|
|
225 |
$this->sql_transaction('begin'); |
|
226 |
}
|
|
227 |
else
|
|
228 |
{
|
|
229 |
$in_transaction = true; |
|
230 |
}
|
|
231 |
||
232 |
$array = array(); |
|
233 |
||
234 |
// We overcome Oracle's 4000 char limit by binding vars
|
|
235 |
if (strlen($query) > 4000) |
|
236 |
{
|
|
237 |
if (preg_match('/^(INSERT INTO[^(]++)\\(([^()]+)\\) VALUES[^(]++\\((.*?)\\)$/s', $query, $regs)) |
|
238 |
{
|
|
239 |
if (strlen($regs[3]) > 4000) |
|
240 |
{
|
|
241 |
$cols = explode(', ', $regs[2]); |
|
242 |
preg_match_all('/\'(?:[^\']++|\'\')*+\'|[\d-.]+/', $regs[3], $vals, PREG_PATTERN_ORDER); |
|
243 |
||
244 |
$inserts = $vals[0]; |
|
245 |
unset($vals); |
|
246 |
||
247 |
foreach ($inserts as $key => $value) |
|
248 |
{
|
|
249 |
if (!empty($value) && $value[0] === "'" && strlen($value) > 4002) // check to see if this thing is greater than the max + 'x2 |
|
250 |
{
|
|
251 |
$inserts[$key] = ':' . strtoupper($cols[$key]); |
|
252 |
$array[$inserts[$key]] = str_replace("''", "'", substr($value, 1, -1)); |
|
253 |
}
|
|
254 |
}
|
|
255 |
||
256 |
$query = $regs[1] . '(' . $regs[2] . ') VALUES (' . implode(', ', $inserts) . ')'; |
|
257 |
}
|
|
258 |
}
|
|
259 |
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)) |
|
260 |
{
|
|
261 |
if (strlen($data[0][2]) > 4000) |
|
262 |
{
|
|
263 |
$update = $data[0][1]; |
|
264 |
$where = $data[0][3]; |
|
265 |
preg_match_all('/([\\w_]++)\\s*=\\s*(\'(?:[^\']++|\'\')*+\'|[\d-.]++)/', $data[0][2], $temp, PREG_SET_ORDER); |
|
266 |
unset($data); |
|
267 |
||
268 |
$cols = array(); |
|
269 |
foreach ($temp as $value) |
|
270 |
{
|
|
271 |
if (!empty($value[2]) && $value[2][0] === "'" && strlen($value[2]) > 4002) // check to see if this thing is greater than the max + 'x2 |
|
272 |
{
|
|
273 |
$cols[] = $value[1] . '=:' . strtoupper($value[1]); |
|
274 |
$array[$value[1]] = str_replace("''", "'", substr($value[2], 1, -1)); |
|
275 |
}
|
|
276 |
else
|
|
277 |
{
|
|
278 |
$cols[] = $value[1] . '=' . $value[2]; |
|
279 |
}
|
|
280 |
}
|
|
281 |
||
282 |
$query = $update . implode(', ', $cols) . ' ' . $where; |
|
283 |
unset($cols); |
|
284 |
}
|
|
285 |
}
|
|
286 |
}
|
|
287 |
||
288 |
switch (substr($query, 0, 6)) |
|
289 |
{
|
|
290 |
case 'DELETE': |
|
291 |
if (preg_match('/^(DELETE FROM [\w_]++ WHERE)((?:\s*(?:AND|OR)?\s*[\w_]+\s*(?:(?:=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]+)|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]+,? ?)*+\)))*+)$/', $query, $regs)) |
|
292 |
{
|
|
293 |
$query = $regs[1] . $this->_rewrite_where($regs[2]); |
|
294 |
unset($regs); |
|
295 |
}
|
|
296 |
break; |
|
297 |
||
298 |
case 'UPDATE': |
|
299 |
if (preg_match('/^(UPDATE [\\w_]++\\s+SET [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++)(?:, [\\w_]+\s*=\s*(?:\'(?:[^\']++|\'\')*+\'|[\d-.]++|:\w++))*+\\s+WHERE)(.*)$/s', $query, $regs)) |
|
300 |
{
|
|
301 |
$query = $regs[1] . $this->_rewrite_where($regs[2]); |
|
302 |
unset($regs); |
|
303 |
}
|
|
304 |
break; |
|
305 |
||
306 |
case 'SELECT': |
|
307 |
$query = preg_replace_callback('/([\w_.]++)\s*(?:(=|<>)\s*(?>\'(?>[^\']++|\'\')*+\'|[\d-.]++|([\w_.]++))|(?:NOT )?IN\s*\((?>\'(?>[^\']++|\'\')*+\',? ?|[\d-.]++,? ?)*+\))/', array($this, '_rewrite_col_compare'), $query); |
|
308 |
break; |
|
309 |
}
|
|
310 |
||
311 |
$this->query_result = @ociparse($this->db_connect_id, $query); |
|
312 |
||
313 |
foreach ($array as $key => $value) |
|
314 |
{
|
|
315 |
@ocibindbyname($this->query_result, $key, $array[$key], -1); |
|
316 |
}
|
|
317 |
||
318 |
$success = @ociexecute($this->query_result, OCI_DEFAULT); |
|
319 |
||
320 |
if (!$success) |
|
321 |
{
|
|
322 |
$this->sql_error($query); |
|
323 |
$this->query_result = false; |
|
324 |
}
|
|
325 |
else
|
|
326 |
{
|
|
327 |
if (!$in_transaction) |
|
328 |
{
|
|
329 |
$this->sql_transaction('commit'); |
|
330 |
}
|
|
331 |
}
|
|
332 |
||
333 |
if (defined('DEBUG_EXTRA')) |
|
334 |
{
|
|
335 |
$this->sql_report('stop', $query); |
|
336 |
}
|
|
337 |
||
338 |
if ($cache_ttl && method_exists($cache, 'sql_save')) |
|
339 |
{
|
|
340 |
$this->open_queries[(int) $this->query_result] = $this->query_result; |
|
341 |
$cache->sql_save($query, $this->query_result, $cache_ttl); |
|
342 |
}
|
|
343 |
else if (strpos($query, 'SELECT') === 0 && $this->query_result) |
|
344 |
{
|
|
345 |
$this->open_queries[(int) $this->query_result] = $this->query_result; |
|
346 |
}
|
|
347 |
}
|
|
348 |
else if (defined('DEBUG_EXTRA')) |
|
349 |
{
|
|
350 |
$this->sql_report('fromcache', $query); |
|
351 |
}
|
|
352 |
}
|
|
353 |
else
|
|
354 |
{
|
|
355 |
return false; |
|
356 |
}
|
|
357 |
||
358 |
return ($this->query_result) ? $this->query_result : false; |
|
359 |
}
|
|
360 |
||
361 |
/**
|
|
362 |
* Build LIMIT query
|
|
363 |
*/
|
|
364 |
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0) |
|
365 |
{
|
|
366 |
$this->query_result = false; |
|
367 |
||
368 |
$query = 'SELECT * FROM (SELECT /*+ FIRST_ROWS */ rownum AS xrownum, a.* FROM (' . $query . ') a WHERE rownum <= ' . ($offset + $total) . ') WHERE xrownum >= ' . $offset; |
|
369 |
||
370 |
return $this->sql_query($query, $cache_ttl); |
|
371 |
}
|
|
372 |
||
373 |
/**
|
|
374 |
* Return number of affected rows
|
|
375 |
*/
|
|
376 |
function sql_affectedrows() |
|
377 |
{
|
|
378 |
return ($this->query_result) ? @ocirowcount($this->query_result) : false; |
|
379 |
}
|
|
380 |
||
381 |
/**
|
|
382 |
* Fetch current row
|
|
383 |
*/
|
|
384 |
function sql_fetchrow($query_id = false) |
|
385 |
{
|
|
386 |
global $cache; |
|
387 |
||
388 |
if ($query_id === false) |
|
389 |
{
|
|
390 |
$query_id = $this->query_result; |
|
391 |
}
|
|
392 |
||
393 |
if (isset($cache->sql_rowset[$query_id])) |
|
394 |
{
|
|
395 |
return $cache->sql_fetchrow($query_id); |
|
396 |
}
|
|
397 |
||
398 |
if ($query_id !== false) |
|
399 |
{
|
|
400 |
$row = array(); |
|
401 |
$result = @ocifetchinto($query_id, $row, OCI_ASSOC + OCI_RETURN_NULLS); |
|
402 |
||
403 |
if (!$result || !$row) |
|
404 |
{
|
|
405 |
return false; |
|
406 |
}
|
|
407 |
||
408 |
$result_row = array(); |
|
409 |
foreach ($row as $key => $value) |
|
410 |
{
|
|
411 |
// Oracle treats empty strings as null
|
|
412 |
if (is_null($value)) |
|
413 |
{
|
|
414 |
$value = ''; |
|
415 |
}
|
|
416 |
||
417 |
// OCI->CLOB?
|
|
418 |
if (is_object($value)) |
|
419 |
{
|
|
420 |
$value = $value->load(); |
|
421 |
}
|
|
422 |
||
423 |
$result_row[strtolower($key)] = $value; |
|
424 |
}
|
|
425 |
||
426 |
return $result_row; |
|
427 |
}
|
|
428 |
||
429 |
return false; |
|
430 |
}
|
|
431 |
||
432 |
/**
|
|
433 |
* Seek to given row number
|
|
434 |
* rownum is zero-based
|
|
435 |
*/
|
|
436 |
function sql_rowseek($rownum, &$query_id) |
|
437 |
{
|
|
438 |
global $cache; |
|
439 |
||
440 |
if ($query_id === false) |
|
441 |
{
|
|
442 |
$query_id = $this->query_result; |
|
443 |
}
|
|
444 |
||
445 |
if (isset($cache->sql_rowset[$query_id])) |
|
446 |
{
|
|
447 |
return $cache->sql_rowseek($rownum, $query_id); |
|
448 |
}
|
|
449 |
||
450 |
if ($query_id === false) |
|
451 |
{
|
|
452 |
return false; |
|
453 |
}
|
|
454 |
||
455 |
// Reset internal pointer
|
|
456 |
@ociexecute($query_id, OCI_DEFAULT); |
|
457 |
||
458 |
// We do not fetch the row for rownum == 0 because then the next resultset would be the second row
|
|
459 |
for ($i = 0; $i < $rownum; $i++) |
|
460 |
{
|
|
461 |
if (!$this->sql_fetchrow($query_id)) |
|
462 |
{
|
|
463 |
return false; |
|
464 |
}
|
|
465 |
}
|
|
466 |
||
467 |
return true; |
|
468 |
}
|
|
469 |
||
470 |
/**
|
|
471 |
* Get last inserted id after insert statement
|
|
472 |
*/
|
|
473 |
function sql_nextid() |
|
474 |
{
|
|
475 |
$query_id = $this->query_result; |
|
476 |
||
477 |
if ($query_id !== false && $this->last_query_text != '') |
|
478 |
{
|
|
479 |
if (preg_match('#^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)#is', $this->last_query_text, $tablename)) |
|
480 |
{
|
|
481 |
$query = 'SELECT ' . $tablename[1] . '_seq.currval FROM DUAL'; |
|
482 |
$stmt = @ociparse($this->db_connect_id, $query); |
|
483 |
@ociexecute($stmt, OCI_DEFAULT); |
|
484 |
||
485 |
$temp_result = @ocifetchinto($stmt, $temp_array, OCI_ASSOC + OCI_RETURN_NULLS); |
|
486 |
@ocifreestatement($stmt); |
|
487 |
||
488 |
if ($temp_result) |
|
489 |
{
|
|
490 |
return $temp_array['CURRVAL']; |
|
491 |
}
|
|
492 |
else
|
|
493 |
{
|
|
494 |
return false; |
|
495 |
}
|
|
496 |
}
|
|
497 |
}
|
|
498 |
||
499 |
return false; |
|
500 |
}
|
|
501 |
||
502 |
/**
|
|
503 |
* Free sql result
|
|
504 |
*/
|
|
505 |
function sql_freeresult($query_id = false) |
|
506 |
{
|
|
507 |
global $cache; |
|
508 |
||
509 |
if ($query_id === false) |
|
510 |
{
|
|
511 |
$query_id = $this->query_result; |
|
512 |
}
|
|
513 |
||
514 |
if (isset($cache->sql_rowset[$query_id])) |
|
515 |
{
|
|
516 |
return $cache->sql_freeresult($query_id); |
|
517 |
}
|
|
518 |
||
519 |
if (isset($this->open_queries[(int) $query_id])) |
|
520 |
{
|
|
521 |
unset($this->open_queries[(int) $query_id]); |
|
522 |
return @ocifreestatement($query_id); |
|
523 |
}
|
|
524 |
||
525 |
return false; |
|
526 |
}
|
|
527 |
||
528 |
/**
|
|
529 |
* Escape string used in sql query
|
|
530 |
*/
|
|
531 |
function sql_escape($msg) |
|
532 |
{
|
|
533 |
return str_replace("'", "''", $msg); |
|
534 |
}
|
|
535 |
||
536 |
/**
|
|
537 |
* Build LIKE expression
|
|
538 |
* @access private
|
|
539 |
*/
|
|
540 |
function _sql_like_expression($expression) |
|
541 |
{
|
|
542 |
return $expression . " ESCAPE '\\'"; |
|
543 |
}
|
|
544 |
||
545 |
function _sql_custom_build($stage, $data) |
|
546 |
{
|
|
547 |
return $data; |
|
548 |
}
|
|
549 |
||
550 |
/**
|
|
551 |
* return sql error array
|
|
552 |
* @access private
|
|
553 |
*/
|
|
554 |
function _sql_error() |
|
555 |
{
|
|
556 |
$error = @ocierror(); |
|
557 |
$error = (!$error) ? @ocierror($this->query_result) : $error; |
|
558 |
$error = (!$error) ? @ocierror($this->db_connect_id) : $error; |
|
559 |
||
560 |
if ($error) |
|
561 |
{
|
|
562 |
$this->last_error_result = $error; |
|
563 |
}
|
|
564 |
else
|
|
565 |
{
|
|
566 |
$error = (isset($this->last_error_result) && $this->last_error_result) ? $this->last_error_result : array(); |
|
567 |
}
|
|
568 |
||
569 |
return $error; |
|
570 |
}
|
|
571 |
||
572 |
/**
|
|
573 |
* Close sql connection
|
|
574 |
* @access private
|
|
575 |
*/
|
|
576 |
function _sql_close() |
|
577 |
{
|
|
578 |
return @ocilogoff($this->db_connect_id); |
|
579 |
}
|
|
580 |
||
581 |
/**
|
|
582 |
* Build db-specific report
|
|
583 |
* @access private
|
|
584 |
*/
|
|
585 |
function _sql_report($mode, $query = '') |
|
586 |
{
|
|
587 |
switch ($mode) |
|
588 |
{
|
|
589 |
case 'start': |
|
590 |
||
591 |
$html_table = false; |
|
592 |
||
593 |
// Grab a plan table, any will do
|
|
594 |
$sql = "SELECT table_name |
|
595 |
FROM USER_TABLES
|
|
596 |
WHERE table_name LIKE '%PLAN_TABLE%'"; |
|
597 |
$stmt = ociparse($this->db_connect_id, $sql); |
|
598 |
ociexecute($stmt); |
|
599 |
$result = array(); |
|
600 |
||
601 |
if (ocifetchinto($stmt, $result, OCI_ASSOC + OCI_RETURN_NULLS)) |
|
602 |
{
|
|
603 |
$table = $result['TABLE_NAME']; |
|
604 |
||
605 |
// This is the statement_id that will allow us to track the plan
|
|
606 |
$statement_id = substr(md5($query), 0, 30); |
|
607 |
||
608 |
// Remove any stale plans
|
|
609 |
$stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); |
|
610 |
ociexecute($stmt2); |
|
611 |
ocifreestatement($stmt2); |
|
612 |
||
613 |
// Explain the plan
|
|
614 |
$sql = "EXPLAIN PLAN |
|
615 |
SET STATEMENT_ID = '$statement_id' |
|
616 |
FOR $query"; |
|
617 |
$stmt2 = ociparse($this->db_connect_id, $sql); |
|
618 |
ociexecute($stmt2); |
|
619 |
ocifreestatement($stmt2); |
|
620 |
||
621 |
// Get the data from the plan
|
|
622 |
$sql = "SELECT operation, options, object_name, object_type, cardinality, cost |
|
623 |
FROM plan_table
|
|
624 |
START WITH id = 0 AND statement_id = '$statement_id' |
|
625 |
CONNECT BY PRIOR id = parent_id
|
|
626 |
AND statement_id = '$statement_id'"; |
|
627 |
$stmt2 = ociparse($this->db_connect_id, $sql); |
|
628 |
ociexecute($stmt2); |
|
629 |
||
630 |
$row = array(); |
|
631 |
while (ocifetchinto($stmt2, $row, OCI_ASSOC + OCI_RETURN_NULLS)) |
|
632 |
{
|
|
633 |
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row); |
|
634 |
}
|
|
635 |
||
636 |
ocifreestatement($stmt2); |
|
637 |
||
638 |
// Remove the plan we just made, we delete them on request anyway
|
|
639 |
$stmt2 = ociparse($this->db_connect_id, "DELETE FROM $table WHERE statement_id='$statement_id'"); |
|
640 |
ociexecute($stmt2); |
|
641 |
ocifreestatement($stmt2); |
|
642 |
}
|
|
643 |
||
644 |
ocifreestatement($stmt); |
|
645 |
||
646 |
if ($html_table) |
|
647 |
{
|
|
648 |
$this->html_hold .= '</table>'; |
|
649 |
}
|
|
650 |
||
651 |
break; |
|
652 |
||
653 |
case 'fromcache': |
|
654 |
$endtime = explode(' ', microtime()); |
|
655 |
$endtime = $endtime[0] + $endtime[1]; |
|
656 |
||
657 |
$result = @ociparse($this->db_connect_id, $query); |
|
658 |
$success = @ociexecute($result, OCI_DEFAULT); |
|
659 |
$row = array(); |
|
660 |
||
661 |
while (@ocifetchinto($result, $row, OCI_ASSOC + OCI_RETURN_NULLS)) |
|
662 |
{
|
|
663 |
// Take the time spent on parsing rows into account
|
|
664 |
}
|
|
665 |
@ocifreestatement($result); |
|
666 |
||
667 |
$splittime = explode(' ', microtime()); |
|
668 |
$splittime = $splittime[0] + $splittime[1]; |
|
669 |
||
670 |
$this->sql_report('record_fromcache', $query, $endtime, $splittime); |
|
671 |
||
672 |
break; |
|
673 |
}
|
|
674 |
}
|
|
675 |
}
|
|
676 |
||
677 |
?>
|