Author: Mighty Gorgon
(2010/08/20 22:58) Over 1 year ago
Fixed some bugs in update procedure
62
include(IP_ROOT_PATH . 'config.' . PHP_EXT);
63
include('includes/constants.' . PHP_EXT);
64
include('includes/functions.' . PHP_EXT);
65
//include('includes/db.' . PHP_EXT);
include('includes/db.' . PHP_EXT);
66
//include('includes/utf/utf_tools.' . PHP_EXT);
67
/*
include(IP_ROOT_PATH . 'includes/db.' . PHP_EXT);
68
69
*/
include(IP_ROOT_PATH . 'includes/utf/utf_tools.' . PHP_EXT);
70
}
71
72
26
include('includes/mysql.' . PHP_EXT);
27
break;
28
case 'mysql4':
29
include('includes/mysql4.' . PHP_EXT);
30
31
32
15
*
16
17
18
if(!defined('SQL_LAYER'))
if (!defined('IN_ICYPHOENIX'))
19
{
20
exit;
21
22
define('SQL_LAYER', 'mysql');
23
class sql_db
24
25
var $db_connect_id;
var $query_string = '';
var $query_result;
var $row = array();
var $rowset = array();
var $num_queries = 0;
var $num_queries = array();
var $open_queries = array();
var $transaction = false;
33
var $transactions = 0;
34
var $persistency = false;
35
var $multi_insert = false;
36
//
37
var $cache_folder = '';
38
39
var $curtime = 0;
40
var $sql_time = 0;
41
var $sql_init_time = 0;
42
var $sql_start_time = 0;
43
var $sql_end_time = 0;
44
45
var $query_hold = '';
46
var $html_hold = '';
47
var $sql_report = '';
48
49
var $return_on_error = false;
50
var $sql_error_triggered = false; // Set to true if error triggered
51
var $sql_error_sql = ''; // Holding the last sql query on sql error
52
var $sql_error_returned = array(); // Holding the error information - only populated if sql_error_triggered is set
53
54
/**
55
* Exact version of the DBAL, directly queried
56
57
var $sql_server_version = false;
58
59
60
* Wildcards for matching any (%) or exactly one (_) character within LIKE expressions
61
var $any_char;
var $one_char;
// Constructor
function sql_db($sqlserver, $sqluser, $sqlpassword, $database, $persistency = true)
$this->sql_start_time = $this->sql_get_time();
$this->sql_init_time = $this->sql_start_time;
$this->num_queries = array(
'cached' => 0,
73
'normal' => 0,
74
'total' => 0,
75
);
76
77
// Fill default sql layer based on the class being called.
78
// This can be changed by the specified layer itself later if needed.
79
$this->sql_layer = SQL_LAYER;
80
81
// Do not change this please! This variable is used to easy the use of it - and is hardcoded.
82
$this->any_char = chr(0) . '%';
83
$this->one_char = chr(0) . '_';
84
$this->persistency = $persistency;
85
$this->user = $sqluser;
86
$this->password = $sqlpassword;
87
$this->server = $sqlserver;
88
$this->dbname = $database;
89
90
if($this->persistency)
91
$this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $this->password) : @mysql_connect($this->server, $this->user, $this->password);
92
$this->db_connect_id = @mysql_pconnect($this->server, $this->user, $this->password);
else
$this->db_connect_id = @mysql_connect($this->server, $this->user, $this->password);
if($this->db_connect_id)
93
94
if($database != "")
95
if($database != '')
96
97
$dbselect = @mysql_select_db($this->dbname);
98
99
if(!$dbselect)
100
101
@mysql_close($this->db_connect_id);
102
$this->db_connect_id = $dbselect;
103
104
105
return $this->db_connect_id;
106
107
$result = $this->db_connect_id;
108
109
110
return false;
111
$this->sql_error('');
112
$result = false;
113
114
115
// make db connection UTF-8 aware
116
if ($this->db_connect_id)
117
118
@mysql_query("SET NAMES 'utf8'");
119
120
121
$this->sql_server_version = $this->sql_server_info(true);
122
123
$this->sql_end_time = $this->sql_get_time();
124
$this->sql_time += $this->sql_end_time - $this->sql_start_time;
125
126
return $result;
127
128
129
// Other base methods
130
* Version information about used database
131
* @param bool $raw if true, only return the fetched sql_server_version
132
* @return string sql server version
133
134
function sql_server_info($raw = false)
135
136
global $cache;
137
138
if (empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false)
139
140
$result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id);
141
$row = @mysql_fetch_assoc($result);
142
@mysql_free_result($result);
143
144
$this->sql_server_version = $row['version'];
145
146
if (!empty($cache))
147
148
$cache->put('mysql_version', $this->sql_server_version);
149
150
151
152
return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version;
153
154
155
156
* Get microtime
157
158
function sql_get_time()
159
160
$mtime = explode(' ', microtime());
161
return $mtime[1] + $mtime[0];
162
163
164
165
* Close DB connection
166
function sql_close()
167
168
169
170
171
172
if($this->query_result)
173
// Commit any remaining transactions
174
if($this->transaction)
175
@mysql_free_result($this->query_result);
176
do
177
178
$this->sql_transaction('commit');
179
180
while ($this->transaction);
181
$result = @mysql_close($this->db_connect_id);
182
183
foreach ($this->open_queries as $query_id)
184
185
$this->sql_freeresult($query_id);
186
187
188
// Connection closed correctly. Set db_connect_id to false to prevent errors
189
if ($result = $this->_sql_close())
190
191
$this->db_connect_id = false;
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
* Return number of sql queries and cached sql queries used
207
208
function sql_num_queries($cached = false)
209
210
return ($cached) ? $this->num_queries['cached'] : $this->num_queries['normal'];
211
212
213
214
* Add to query count
215
216
function sql_add_num_queries($cached = false)
217
218
$this->num_queries['cached'] += ($cached !== false) ? 1 : 0;
219
$this->num_queries['normal'] += ($cached !== false) ? 0 : 1;
220
$this->num_queries['total'] += 1;
221
222
223
224
* Build LIMIT query
225
* Doing some validation here.
226
227
function sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
228
229
if (empty($query))
230
231
232
233
234
// Never use a negative total or offset
235
$total = ($total < 0) ? 0 : $total;
236
$offset = ($offset < 0) ? 0 : $offset;
237
238
return $this->_sql_query_limit($query, $total, $offset, $cache_ttl);
239
240
241
// Base query method
242
* Base query method
243
function sql_query($query = "", $transaction = FALSE)
244
function sql_query($query = '', $cache_ttl = 0, $cache_prefix = false, $cache_folder = SQL_CACHE_FOLDER)
245
// Remove any pre-existing queries
246
unset($this->query_result);
if($query != "")
247
$this->num_queries++;
248
249
250
$this->query_result = @mysql_query($query, $this->db_connect_id);
251
252
253
254
255
$cache_folder = (empty($cache_folder) ? SQL_CACHE_FOLDER : $cache_folder);
256
257
if (defined('DEBUG_EXTRA'))
258
259
$this->sql_report('start', $query);
260
261
262
if (CACHE_SQL == false)
263
unset($this->row[$this->query_result]);
264
$cache_prefix = false;
unset($this->rowset[$this->query_result]);
return $this->query_result;
265
266
267
$cache_ttl = empty($cache_prefix) ? 0 : (empty($cache_ttl) ? CACHE_SQL_EXPIRY : $cache_ttl);
268
269
// Cache SQL to the same file plus underscore
270
if (defined('SQL_DEBUG_LOG') && SQL_DEBUG_LOG && !defined('IN_ADMIN'))
271
return ( $transaction == END_TRANSACTION ) ? true : false;
272
$f = fopen($this->cache_folder . 'sql_history.' . PHP_EXT, 'a+');
273
@flock($f, LOCK_EX);
274
@fwrite($f, gmdate('Y/m/d - H:i:s') . ' => ' . $hash . "\n\n" . $query . "\n\n\n=========================\n\n");
275
@flock($f, LOCK_UN);
276
@fclose($f);
277
278
279
$this->query_result = ($cache_ttl && method_exists($cache, 'sql_load')) ? $cache->sql_load($query, $cache_prefix, $cache_folder) : false;
280
$this->sql_add_num_queries($this->query_result);
281
282
if ($this->query_result === false)
283
284
if ((($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) && !defined('IN_INSTALL'))
285
286
287
288
289
$this->sql_error($query);
290
291
292
293
294
295
296
297
$this->sql_report('stop', $query);
298
299
300
if ($cache_ttl && method_exists($cache, 'sql_save'))
301
302
$this->open_queries[(int) $this->query_result] = $this->query_result;
303
$cache->sql_save($query, $this->query_result, $cache_ttl, $cache_prefix, $cache_folder);
304
305
elseif (strpos($query, 'SELECT') === 0 && $this->query_result)
306
307
308
309
310
elseif (defined('DEBUG_EXTRA'))
311
312
$this->sql_report('fromcache', $query);
313
314
315
316
317
318
319
320
321
// Other query methods
322
* Get numrows
323
function sql_numrows($query_id = 0)
324
325
if(!$query_id)
326
327
$query_id = $this->query_result;
328
329
if($query_id)
330
331
return ($query_id) ? @mysql_num_rows($query_id) : false;
$result = @mysql_num_rows($query_id);
332
333
334
335
* Get affected rows
336
function sql_affectedrows()
337
338
339
return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false;
340
341
342
343
* Fetch current row
344
345
function sql_fetchrow($query_id = false)
346
347
348
349
if ($query_id === false)
350
$result = @mysql_affected_rows($this->db_connect_id);
351
352
353
354
if (isset($cache->sql_rowset[$query_id]))
355
356
return $cache->sql_fetchrow($query_id);
357
358
359
return ($query_id !== false) ? @mysql_fetch_assoc($query_id) : false;
360
361
function sql_numfields($query_id = 0)
362
363
* Fetch all rows
364
365
function sql_fetchrowset($query_id = false)
366
367
368
369
370
371
372
373
if ($query_id !== false)
374
$result = @mysql_num_fields($query_id);
375
$result = array();
376
while ($row = $this->sql_fetchrow($query_id))
377
378
$result[] = $row;
379
380
381
382
383
384
385
386
function sql_fieldname($offset, $query_id = 0)
387
388
* Fetch field
389
* if rownum is false, the current row is used, else it is pointing to the row (zero-based)
390
391
function sql_fetchfield($field, $rownum = false, $query_id = false)
392
393
394
395
396
397
398
399
400
401
402
$result = @mysql_field_name($query_id, $offset);
403
if ($rownum !== false)
404
405
$this->sql_rowseek($rownum, $query_id);
406
407
408
if (!is_object($query_id) && isset($cache->sql_rowset[$query_id]))
409
410
return $cache->sql_fetchfield($query_id, $field);
411
412
413
$row = $this->sql_fetchrow($query_id);
414
$result = (isset($row[$field])) ? $row[$field] : false;
415
416
417
418
419
function sql_fieldtype($offset, $query_id = 0)
420
421
* Get num fields
422
423
424
425
426
427
428
429
430
return ($query_id) ? @mysql_num_fields($query_id) : false;
$result = @mysql_field_type($query_id, $offset);
431
432
function sql_fetchrow($query_id = 0)
433
434
* Get field name
435
436
437
438
439
440
441
442
443
return ($query_id) ? @mysql_field_name($query_id, $offset) : false;
$this->row[$query_id] = @mysql_fetch_array($query_id);
return $this->row[$query_id];
444
445
function sql_fetchrowset($query_id = 0)
446
447
* Get field type
448
449
450
451
452
453
454
455
456
return ($query_id) ? @mysql_field_type($query_id, $offset) : false;
unset($this->rowset[$query_id]);
unset($this->row[$query_id]);
while($this->rowset[$query_id] = @mysql_fetch_array($query_id))
$result[] = $this->rowset[$query_id];
457
458
function sql_fetchfield($field, $rownum = -1, $query_id = 0)
459
460
* Seek to given row number
461
* rownum is zero-based
462
463
function sql_rowseek($rownum, &$query_id)
464
465
466
467
468
469
470
471
472
473
if($rownum > -1)
474
return $cache->sql_rowseek($rownum, $query_id);
$result = @mysql_result($query_id, $rownum, $field);
if(empty($this->row[$query_id]) && empty($this->rowset[$query_id]))
if($this->sql_fetchrow())
$result = $this->row[$query_id][$field];
if($this->rowset[$query_id])
$result = $this->rowset[$query_id][0][$field];
else if($this->row[$query_id])
475
476
477
return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false;
478
479
480
481
* Get last inserted id after insert statement
482
483
function sql_nextid()
484
485
return ($this->db_connect_id) ? @mysql_insert_id($this->db_connect_id) : false;
486
487
488
* Function for validating values
489
490
function sql_validate_value($var)
491
...
518
519
520
521
* Correctly adjust LIKE expression for special characters
522
* Some DBMS are handling them in a different way
523
524
* @param string $expression The expression to use. Every wildcard is escaped, except $this->any_char and $this->one_char
525
* @return string LIKE expression including the keyword!
526
527
function sql_like_expression($expression)
528
529
$expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);
530
$expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);
531
532
return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');
533
534
535
536
* Build sql statement from array for select and select distinct statements
537
538
* Possible query values: SELECT, SELECT_DISTINCT
539
540
function sql_build_query($query, $array)
541
542
$sql = '';
543
switch ($query)
544
545
case 'SELECT':
546
case 'SELECT_DISTINCT';
547
548
$sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';
549
550
// Build table array. We also build an alias array for later checks.
551
$table_array = $aliases = array();
552
$used_multi_alias = false;
553
554
foreach ($array['FROM'] as $table_name => $alias)
555
556
if (is_array($alias))
557
558
$used_multi_alias = true;
559
560
foreach ($alias as $multi_alias)
561
562
$table_array[] = $table_name . ' ' . $multi_alias;
563
$aliases[] = $multi_alias;
564
565
566
567
568
$table_array[] = $table_name . ' ' . $alias;
569
$aliases[] = $alias;
570
571
572
573
// We run the following code to determine if we need to re-order the table array. ;)
574
// The reason for this is that for multi-aliased tables (two equal tables) in the FROM statement the last table need to match the first comparison.
575
// DBMS who rely on this: Oracle, PostgreSQL and MSSQL. For all other DBMS it makes absolutely no difference in which order the table is.
576
if (!empty($array['LEFT_JOIN']) && sizeof($array['FROM']) > 1 && $used_multi_alias !== false)
577
578
// Take first LEFT JOIN
579
$join = current($array['LEFT_JOIN']);
580
581
// Determine the table used there (even if there are more than one used, we only want to have one
582
preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);
583
584
// If there is a first join match, we need to make sure the table order is correct
585
if (!empty($matches[1]))
586
587
$first_join_match = trim($matches[1]);
588
$table_array = $last = array();
589
590
591
592
593
594
595
596
($multi_alias === $first_join_match) ? $last[] = $table_name . ' ' . $multi_alias : $table_array[] = $table_name . ' ' . $multi_alias;
597
598
599
600
601
($alias === $first_join_match) ? $last[] = $table_name . ' ' . $alias : $table_array[] = $table_name . ' ' . $alias;
602
603
604
605
$table_array = array_merge($table_array, $last);
606
607
608
609
$sql .= $this->_sql_custom_build('FROM', implode(', ', $table_array));
610
611
if (!empty($array['LEFT_JOIN']))
612
613
foreach ($array['LEFT_JOIN'] as $join)
614
615
$sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';
616
617
618
619
if (!empty($array['WHERE']))
620
621
$sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);
622
623
624
if (!empty($array['GROUP_BY']))
625
626
$sql .= ' GROUP BY ' . $array['GROUP_BY'];
627
628
629
if (!empty($array['ORDER_BY']))
630
631
$sql .= ' ORDER BY ' . $array['ORDER_BY'];
632
633
634
635
636
637
return $sql;
638
639
640
641
* Build SQL to INSERT or UPDATE from the provided array
642
643
function sql_build_insert_update($sql_input_array, $sql_insert = true)
644
645
$insert_fields_sql = '';
646
$insert_values_sql = '';
647
$update_sql = '';
648
foreach ($sql_input_array as $k => $v)
649
650
$insert_fields_sql .= (($insert_fields_sql == '') ? '' : ', ') . $k;
651
$insert_values_sql .= (($insert_values_sql == '') ? '' : ', ') . $this->sql_validate_value($v);
652
$update_sql .= (($update_sql == '') ? '' : ', ') . $k . ' = ' . $this->sql_validate_value($v);
653
654
655
$sql_string = $sql_insert ? (' (' . $insert_fields_sql . ') VALUES (' . $insert_values_sql . ')') : $update_sql;
656
657
return $sql_string;
658
659
660
* Build sql statement from array for insert/update/select statements
661
662
* Idea for this from Ikonboard
663
return $query;
709
710
711
function sql_rowseek($rownum, $query_id = 0){
712
713
* Build IN or NOT IN sql comparison string, uses <> or = on single element arrays to improve comparison speed
714
715
* @access public
716
* @param string $field name of the sql column that shall be compared
717
* @param array $array array of values that are allowed (IN) or not allowed (NOT IN)
718
* @param bool $negate true for NOT IN (), false for IN () (default)
719
* @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false.
720
721
function sql_in_set($field, $array, $negate = false, $allow_empty_set = false)
722
723
if (!sizeof($array))
724
725
if (!$allow_empty_set)
726
727
// Print the backtrace to help identifying the location of the problematic code
728
$this->sql_error('No values specified for SQL IN comparison');
729
730
731
732
// NOT IN () actually means everything so use a tautology
733
if ($negate)
734
735
return '1=1';
736
737
// IN () actually means nothing so use a contradiction
738
739
740
return '1=0';
741
742
743
744
745
if (!is_array($array))
746
$result = @mysql_data_seek($query_id, $rownum);
747
$array = array($array);
748
749
750
if (sizeof($array) == 1)
751
752
@reset($array);
753
$var = current($array);
754
755
return $field . ($negate ? ' <> ' : ' = ') . $this->sql_validate_value($var);
756
757
758
759
return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, 'sql_validate_value'), $array)) . ')';
760
761
762
function sql_nextid(){
763
764
* Run more than one insert statement.
765
766
* @param string $table table name to run the statements on
767
* @param array &$sql_ary multi-dimensional array holding the statement data.
768
769
* @return bool false if no statements were executed.
770
771
772
function sql_multi_insert($table, &$sql_ary)
773
774
if (!sizeof($sql_ary))
775
$result = @mysql_insert_id($this->db_connect_id);
776
777
778
779
if ($this->multi_insert)
780
781
$ary = array();
782
foreach ($sql_ary as $id => $_sql_ary)
783
784
// If by accident the sql array is only one-dimensional we build a normal insert statement
785
if (!is_array($_sql_ary))
786
787
$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));
788
return true;
789
790
791
$values = array();
792
foreach ($_sql_ary as $key => $var)
793
794
$values[] = $this->_sql_validate_value($var);
795
796
$ary[] = '(' . implode(', ', $values) . ')';
797
798
799
$this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));
800
801
802
803
foreach ($sql_ary as $ary)
804
805
if (!is_array($ary))
806
807
808
809
810
$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));
811
812
813
814
815
816
function sql_freeresult($query_id = 0){
817
818
* Free sql result
819
820
function sql_freeresult($query_id = false)
821
822
823
824
825
826
827
828
if ( $query_id )
829
830
831
return $cache->sql_freeresult($query_id);
832
833
@mysql_free_result($query_id);
834
if (isset($this->open_queries[(int) $query_id]))
835
836
unset($this->open_queries[(int) $query_id]);
837
return @mysql_free_result($query_id);
838
839
840
841
842
843
844
* Errors handling
845
846
function sql_error($sql = '')
847
848
global $lang;
849
850
// Set var to retrieve errored status
851
$this->sql_error_triggered = true;
852
$this->sql_error_sql = $sql;
853
854
$this->sql_error_returned = $this->_sql_error();
855
856
if (!$this->return_on_error && !defined('IN_INSTALL'))
857
858
$message = '<b>SQL ERROR [ ' . SQL_LAYER . ' ]</b><br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';
859
860
// Show complete SQL error and path to administrators only
861
// Additionally show complete error on installation or if extended debug mode is enabled
862
// The DEBUG_EXTRA constant is for development only!
863
if (defined('IN_INSTALL') || (defined('DEBUG_EXTRA') && (DEBUG_EXTRA == true)))
864
865
$backtrace = get_backtrace();
866
867
$message .= ($sql) ? '<br /><br /><b>SQL</b><br /><br />' . htmlspecialchars($sql) : '';
868
$message .= ($backtrace) ? '<br /><br /><b>BACKTRACE</b><br />' . $backtrace : '';
869
$message .= '<br />';
870
871
872
873
// If error occurs in initiating the session we need to use a pre-defined language string
874
// This could happen if the connection could not be established for example (then we are not able to grab the default language)
875
if (!isset($lang['SQL_ERROR_OCCURRED']))
876
877
$message .= '<br /><br />An sql error occurred while fetching this page. Please contact site administrator if this problem persists.';
878
879
880
881
$message .= '<br /><br />' . $lang['SQL_ERROR_OCCURRED'];
882
883
884
885
if ($this->transaction)
886
887
$this->sql_transaction('rollback');
888
889
890
global $msg_code;
891
$msg_code = CRITICAL_MESSAGE;
892
$message = '<div style="text-align: left;">' . $message . '</div>';
893
894
if (strlen($message) > 1024)
895
896
// We need to define $msg_long_text here to circumvent text stripping.
897
global $msg_long_text;
898
$msg_long_text = $message;
899
900
trigger_error(false, E_USER_NOTICE);
901
902
903
trigger_error($message, E_USER_NOTICE);
904
905
$msg_text = $message;
906
$msg_title = isset($lang['Error']) ? $lang['Error'] : 'Error';
907
message_die($msg_code, $msg_text, $msg_title, __LINE__, __FILE__, $sql);
908
909
910
911
912
913
914
915
916
return $this->sql_error_returned;
917
918
919
921
function sql_return_on_error($fail = false)
922
923
924
$this->sql_error_triggered = false;
925
$this->sql_error_sql = '';
926
927
$this->return_on_error = $fail;
928
929
function sql_error($query_id = 0)
930
931
* SQL Transaction
932
* @access private
933
934
function sql_transaction($status = 'begin')
935
$result["message"] = @mysql_error($this->db_connect_id);
936
switch ($status)
$result["code"] = @mysql_errno($this->db_connect_id);
937
938
case 'begin':
939
// If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit)
940
941
942
$this->transactions++;
943
944
945
946
$result = $this->_sql_transaction('begin');
947
948
if (!$result)
949
950
$this->sql_error();
951
952
953
$this->transaction = true;
954
955
956
case 'commit':
957
// If there was a previously opened transaction we do not commit yet... but count back the number of inner transactions
958
if ($this->transaction && $this->transactions)
959
960
$this->transactions--;
961
962
963
964
// Check if there is a transaction (no transaction can happen if there was an error, with a combined rollback and error returning enabled)
965
// This implies we have transaction always set for autocommit db's
966
if (!$this->transaction)
967
968
969
970
971
$result = $this->_sql_transaction('commit');
972
973
974
975
976
977
978
$this->transaction = false;
979
$this->transactions = 0;
980
981
982
case 'rollback':
983
$result = $this->_sql_transaction('rollback');
984
985
986
987
988
default:
989
$result = $this->_sql_transaction($status);
990
991
992
993
994
995
} // class sql_db
996
997
* Explain queries
998
999
function sql_report($mode, $query = '')
1000
1001
if (empty($_REQUEST['explain']))
1002
1003
1004
1005
} // if ... define
1006
if (!$query && ($this->query_hold != ''))
1007
1008
$query = $this->query_hold;
1009
1010
1011
switch ($mode)
1012
1013
case 'display':
1014
1015
1016
$cache->unload();
1017
1018
$this->sql_close();
1019
1020
1021
$totaltime = $mtime[0] + $mtime[1] - $this->sql_init_time;
1022
echo ('
1023
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1024
<html xmlns="http://www.w3.org/1999/xhtml">
1025
<head>
1026
<link rel="stylesheet" href="' . IP_ROOT_PATH . 'templates/common/acp.css" type="text/css" />
1027
<meta name="author" content="Mighty Gorgon" />
1028
<title>Icy Phoenix</title>
1029
<!--[if lt IE 7]>
1030
<script type="text/javascript" src="' . IP_ROOT_PATH . 'templates/common/js/pngfix.js"></script>
1031
<![endif]-->
1032
</head>
1033
1034
<body>
1035
<a name="top"></a>
1036
<div id="global-wrapper" style="width: 960px; clear: both; margin: 0 auto;">
1037
<div class="leftshadow"><div class="rightshadow"><div id="wrapper-inner">
1038
<table id="forumtable" width="100%" cellspacing="0" cellpadding="0">
1039
<tr>
1040
<td width="100%" colspan="3" valign="top">
1041
<div id="top_logo">
1042
<table class="" width="100%" cellspacing="0" cellpadding="0" border="0">
1043
1044
<td height="150" align="left" valign="middle">
1045
<a href="http://www.icyphoenix.com" title="Icy Phoenix"><img src="' . IP_ROOT_PATH . 'images/logo_ip.png" alt="Icy Phoenix" title="Icy Phoenix" border="0" /></a>
1046
</td>
1047
</tr>
1048
</table>
1049
</div>
1050
1051
1052
<tr><td colspan="3" class="forum-buttons" valign="middle">Icy Phoenix Extra Debug</td></tr>
1053
1054
<td colspan="3" id="content">
1055
<div class="post-text">
1056
<br />
1057
<h1>SQL Report</h1>
1058
1059
<p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p>
1060
<p>Time spent on ' . $this->num_queries['total'] . ' queries: <b>' . round($this->sql_time, 5) . 's</b></p>
1061
<p>Time spent on PHP: <b>' . round($totaltime - $this->sql_time, 5) . 's</b></p>
1062
<br /><br />
1063
' . $this->sql_report . '
1064
1065
1066
1067
1068
<td width="100%" colspan="3">
1069
<div id="bottom_logo_ext">
1070
<div id="bottom_logo">
1071
<table class="empty-table" width="100%" cellspacing="0" cellpadding="0" border="0">
1072
1073
<td nowrap="nowrap" width="45%" align="left">
1074
<br /><span class="copyright"> Powered by <a href="http://www.icyphoenix.com/" target="_blank">Icy Phoenix</a> based on <a href="http://www.phpbb.com/" target="_blank">phpBB</a></span><br /><br />
1075
1076
<td nowrap="nowrap" align="center"><div style="text-align:center;"> </div></td>
1077
<td nowrap="nowrap" width="45%" align="right">
1078
<br /><span class="copyright">Design by <a href="http://www.mightygorgon.com" target="_blank">Mighty Gorgon</a> </span><br /><br />
1079
1080
1081
1082
1083
1084
1085
1086
1087
</div></div></div>
1088
1089
</body>
1090
</html>
1091
');
1092
exit_handler();
1093
1094
1095
1096
case 'stop':
1097
$endtime = explode(' ', microtime());
1098
$endtime = $endtime[0] + $endtime[1];
1099
$this->sql_report .= '
1100
<table class="forumline" width="100%" cellspacing="0" cellpadding="0" border="0">
1101
<thead>
1102
<tr><th>Query #' . $this->num_queries['total'] . '</th></tr>
1103
</thead>
1104
<tbody>
1105
1106
<td class="row1"><textarea style="font-family: \'Courier New\', monospace; width: 99%;" rows="8" cols="160">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td>
1107
1108
</tbody>
1109
1110
' . $this->html_hold . '
1111
<p class="helpline" style="padding: 2px;">
1112
';
1113
if ($this->query_result)
1114
1115
$this->sql_report .= 'Elapsed: <b style="color:#224488;">' . sprintf('%.5f', $endtime - $this->curtime) . 's</b> • [Before: ' . sprintf('%.5f', $this->curtime - $this->sql_start_time) . 's | After: ' . sprintf('%.5f', $endtime - $this->sql_start_time) . 's]';
1116
if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query))
1117
1118
$this->sql_report .= ' - [Affected rows: <b style="color:#224488;">' . $this->sql_affectedrows($this->query_result) . '</b>]';
1119
1120
1121
1122
1123
$error = $this->sql_error();
1124
$this->sql_report .= '<b style="color:#cc3333;">FAILED</b> - ' . SQL_LAYER . ' Error ' . $error['code'] . ': ' . htmlspecialchars($error['message']);
1125
1126
$this->sql_report .= '</p><br /><br />';
1127
$this->sql_time += $endtime - $this->curtime;
1128
1129
1130
case 'start':
1131
$this->query_hold = $query;
1132
$this->html_hold = '';
1133
$this->curtime = explode(' ', microtime());
1134
$this->curtime = $this->curtime[0] + $this->curtime[1];
1135
1136
1137
case 'add_select_row':
1138
1139
$html_table = func_get_arg(2);
1140
$row = func_get_arg(3);
1141
1142
if (!$html_table && sizeof($row))
1143
1144
$html_table = true;
1145
$this->html_hold .= '<table class="forumline" width="100%" cellspacing="0" cellpadding="0" border="0"><tr>';
1146
1147
foreach (array_keys($row) as $val)
1148
1149
$this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>';
1150
1151
$this->html_hold .= '</tr>';
1152
1153
$this->html_hold .= '<tr>';
1154
1155
$class = 'row1';
1156
foreach (array_values($row) as $val)
1157
1158
$class = ($class == 'row1') ? 'row2' : 'row1';
1159
$this->html_hold .= '<td class="' . $class . '">' . (($val) ? $val : ' ') . '</td>';
1160
1161
1162
1163
return $html_table;
1164
1165
1166
1167
case 'fromcache':
1168
1169
$this->_sql_report($mode, $query);
1170
1171
1172
1173
case 'record_fromcache':
1174
1175
$endtime = func_get_arg(2);
1176
$splittime = func_get_arg(3);
1177
1178
$time_cache = $endtime - $this->curtime;
1179
$time_db = $splittime - $endtime;
1180
$color = ($time_db > $time_cache) ? '#228844' : '#cc3333';
1181
1182
$this->sql_report .= '<table class="forumline" width="100%" cellspacing="0" cellpadding="0" border="0">';
1183
$this->sql_report .= '<thead><tr><th>Query #' . $this->num_queries['total'] . ' [From Cache]</th></tr></thead><tbody><tr>';
1184
$this->sql_report .= '<td class="row3"><textarea style="font-family: \'Courier New\', monospace; width: 99%;" rows="8" cols="160">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>';
1185
$this->sql_report .= '<p class="helpline" style="padding: 2px;">';
1186
$this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $this->sql_start_time) . 's | After: ' . sprintf('%.5f', $endtime - $this->sql_start_time) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />';
1187
1188
// Pad the start time to not interfere with page timing
1189
$this->sql_start_time += $time_db;
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
function _sql_query_limit($query, $total, $offset = 0, $cache_ttl = 0)
1205
1206
$this->query_result = false;
1207
1208
// if $total is set to 0 we do not want to limit the number of rows
1209
if ($total == 0)
1210
1211
// Having a value of -1 was always a bug
1212
$total = '18446744073709551615';
1213
1214
1215
$query .= "\n LIMIT " . ((!empty($offset)) ? $offset . ', ' . $total : $total);
1216
1217
return $this->sql_query($query, $cache_ttl);
1218
1219
1220
1221
* Build LIKE expression
1222
1223
1224
function _sql_like_expression($expression)
1225
1226
return $expression;
1227
1228
1229
1230
* Build db-specific query data
1231
1232
1233
function _sql_custom_build($stage, $data)
1234
1235
switch ($stage)
1236
1237
case 'FROM':
1238
$data = '(' . $data . ')';
1239
1240
1241
1242
return $data;
1243
1244
1245
1246
1247
1248
1249
function _sql_transaction($status = 'begin')
1250
1251
1252
1253
1254
return @mysql_query('BEGIN', $this->db_connect_id);
1255
1256
1257
1258
return @mysql_query('COMMIT', $this->db_connect_id);
1259
1260
1261
1262
return @mysql_query('ROLLBACK', $this->db_connect_id);
1263
1264
1265
1266
1267
1268
1269
1270
* return sql error array
1271
1272
1273
function _sql_error()
1274
1275
if (!$this->db_connect_id)
1276
1277
return array(
1278
'message' => @mysql_error(),
1279
'code' => @mysql_errno()
1280
1281
1282
1283
1284
'message' => @mysql_error($this->db_connect_id),
1285
'code' => @mysql_errno($this->db_connect_id)
1286
1287
1288
1289
1290
* Build db-specific report
1291
1292
1293
function _sql_report($mode, $query = '')
1294
1295
static $test_prof;
1296
1297
// current detection method, might just switch to see the existance of INFORMATION_SCHEMA.PROFILING
1298
if ($test_prof === null)
1299
1300
$test_prof = false;
1301
if (version_compare($this->sql_server_info(true), '5.0.37', '>=') && version_compare($this->sql_server_info(true), '5.1', '<'))
1302
1303
$test_prof = true;
1304
1305
1306
1307
1308
1309
1310
1311
$explain_query = $query;
1312
if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
1313
1314
$explain_query = 'SELECT * FROM ' . $m[1] . ' WHERE ' . $m[2];
1315
1316
elseif (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m))
1317
1318
1319
1320
1321
if (preg_match('/^SELECT/', $explain_query))
1322
1323
$html_table = false;
1324
1325
// begin profiling
1326
if ($test_prof)
1327
1328
@mysql_query('SET profiling = 1;', $this->db_connect_id);
1329
1330
1331
if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id))
1332
1333
while ($row = @mysql_fetch_assoc($result))
1334
1335
$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);
1336
1337
1338
1339
1340
if ($html_table)
1341
1342
$this->html_hold .= '</table>';
1343
1344
1345
1346
1347
1348
1349
// get the last profile
1350
if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id))
1351
1352
$this->html_hold .= '<br />';
1353
1354
1355
// make <unknown> HTML safe
1356
if (!empty($row['Source_function']))
1357
1358
$row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']);
1359
1360
1361
// remove unsupported features
1362
foreach ($row as $key => $val)
1363
1364
if ($val === null)
1365
1366
unset($row[$key]);
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
@mysql_query('SET profiling = 0;', $this->db_connect_id);
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
$result = @mysql_query($query, $this->db_connect_id);
1390
while ($void = @mysql_fetch_assoc($result))
1391
1392
// Take the time spent on parsing rows into account
1393
1394
1395
1396
$splittime = explode(' ', microtime());
1397
$splittime = $splittime[0] + $splittime[1];
1398
1399
$this->sql_report('record_fromcache', $query, $endtime, $splittime);
1400
1401
1402
1403
1404
1405
1406
* Close sql connection
1407
1408
1409
function _sql_close()
1410
1411
return @mysql_close($this->db_connect_id);
1412
1413
1414
1415
* Cache clear function
1416
1417
function clear_cache($cache_prefix = '', $cache_folder = SQL_CACHE_FOLDER, $files_per_step = 0)
1418
1419
1420
1421
$cache_prefix = 'sql_' . $cache_prefix;
1422
$cache_folder = (!empty($cache_folder) && @is_dir($cache_folder)) ? $cache_folder : SQL_CACHE_FOLDER;
1423
$cache_folder = ((@is_dir($cache_folder)) ? $cache_folder : @phpbb_realpath($cache_folder));
1424
1425
$res = opendir($cache_folder);
1426
if($res)
1427
1428
$files_counter = 0;
1429
while(($file = readdir($res)) !== false)
1430
1431
if(!@is_dir($file) && (substr($file, 0, strlen($cache_prefix)) === $cache_prefix) && (substr($file, -(strlen(PHP_EXT) + 1)) === '.' . PHP_EXT))
1432
1433
@unlink($cache_folder . $file);
1434
$files_counter++;
1435
1436
if (($files_per_step > 0) && ($files_counter >= $files_per_step))
1437
1438
closedir($res);
1439
return $files_per_step;
1440
1441
1442
1443
@closedir($res);
1444
1445
1446
1447
?>
1448
include('includes/constants.' . PHP_EXT);include('includes/constants.' . PHP_EXT);include('includes/functions.' . PHP_EXT);include('includes/functions.' . PHP_EXT);//include('includes/db.' . PHP_EXT);include('includes/db.' . PHP_EXT);//include('includes/utf/utf_tools.' . PHP_EXT);/*include('includes/mysql.' . PHP_EXT);include('includes/mysql.' . PHP_EXT);include('includes/mysql4.' . PHP_EXT);include('includes/mysql.' . PHP_EXT);if(!defined('SQL_LAYER'))if (!defined('IN_ICYPHOENIX')){{define('SQL_LAYER', 'mysql');{{var $num_queries = 0;var $num_queries = array();var $open_queries = array();var $transaction = false;var $transactions = 0;var $persistency = false;var $multi_insert = false;//var $cache_folder = '';var $curtime = 0;var $sql_time = 0;var $sql_init_time = 0;var $sql_start_time = 0;var $sql_end_time = 0;var $query_hold = '';var $html_hold = '';var $sql_report = '';var $return_on_error = false;var $sql_error_triggered = false; // Set to true if error triggeredvar $sql_error_sql = ''; // Holding the last sql query on sql errorvar $sql_error_returned = array(); // Holding the error information - only populated if sql_error_triggered is set/*** Exact version of the DBAL, directly queried*/var $sql_server_version = false;/*** Wildcards for matching any (%) or exactly one (_) character within LIKE expressions*/var $any_char;var $one_char;//{{if($this->persistency)$this->db_connect_id = ($this->persistency) ? @mysql_pconnect($this->server, $this->user, $this->password) : @mysql_connect($this->server, $this->user, $this->password);{$this->db_connect_id = @mysql_pconnect($this->server, $this->user, $this->password);}else{$this->db_connect_id = @mysql_connect($this->server, $this->user, $this->password);}{{if($database != "")if($database != ''){{{{return $this->db_connect_id;$result = $this->db_connect_id;{{return false;$this->sql_error('');$result = false;{@mysql_query("SET NAMES 'utf8'");///**// Other base methods* Version information about used database//* @param bool $raw if true, only return the fetched sql_server_version* @return string sql server version*/function sql_server_info($raw = false){global $cache;if (empty($cache) || ($this->sql_server_version = $cache->get('mysql_version')) === false){$result = @mysql_query('SELECT VERSION() AS version', $this->db_connect_id);$row = @mysql_fetch_assoc($result);@mysql_free_result($result);$this->sql_server_version = $row['version'];if (!empty($cache)){$cache->put('mysql_version', $this->sql_server_version);}}return ($raw) ? $this->sql_server_version : 'MySQL ' . $this->sql_server_version;}/*** Get microtime*/function sql_get_time(){$mtime = explode(' ', microtime());return $mtime[1] + $mtime[0];}/*** Close DB connection*/{{{{if($this->query_result)// Commit any remaining transactionsif($this->transaction){{@mysql_free_result($this->query_result);do{$this->sql_transaction('commit');}while ($this->transaction);$result = @mysql_close($this->db_connect_id);return $result;foreach ($this->open_queries as $query_id){$this->sql_freeresult($query_id);}// Connection closed correctly. Set db_connect_id to false to prevent errorsif ($result = $this->_sql_close()){$this->db_connect_id = false;}{{{{{{///**// Base query method* Base query method//*/function sql_query($query = "", $transaction = FALSE)function sql_query($query = '', $cache_ttl = 0, $cache_prefix = false, $cache_folder = SQL_CACHE_FOLDER){{// Remove any pre-existing queriesif (empty($query))unset($this->query_result);if($query != ""){{$this->num_queries++;return false;}$this->query_result = @mysql_query($query, $this->db_connect_id);global $cache;$this->sql_start_time = $this->sql_get_time();$cache_folder = (empty($cache_folder) ? SQL_CACHE_FOLDER : $cache_folder);if (defined('DEBUG_EXTRA')){$this->sql_report('start', $query);if($this->query_result)if (CACHE_SQL == false){{unset($this->row[$this->query_result]);$cache_prefix = false;unset($this->rowset[$this->query_result]);return $this->query_result;else$cache_ttl = empty($cache_prefix) ? 0 : (empty($cache_ttl) ? CACHE_SQL_EXPIRY : $cache_ttl);// Cache SQL to the same file plus underscoreif (defined('SQL_DEBUG_LOG') && SQL_DEBUG_LOG && !defined('IN_ADMIN')){{return ( $transaction == END_TRANSACTION ) ? true : false;$f = fopen($this->cache_folder . 'sql_history.' . PHP_EXT, 'a+');@flock($f, LOCK_EX);@fwrite($f, gmdate('Y/m/d - H:i:s') . ' => ' . $hash . "\n\n" . $query . "\n\n\n=========================\n\n");@flock($f, LOCK_UN);@fclose($f);{if ((($this->query_result = @mysql_query($query, $this->db_connect_id)) === false) && !defined('IN_INSTALL')){if (defined('DEBUG_EXTRA')){$this->sql_report('stop', $query);{{elseif (defined('DEBUG_EXTRA')){$this->sql_report('fromcache', $query);///**// Other query methods* Get numrows//*/{{{{if($query_id){return ($query_id) ? @mysql_num_rows($query_id) : false;$result = @mysql_num_rows($query_id);return $result;}else{return false;}{{if($this->db_connect_id)return ($this->db_connect_id) ? @mysql_affected_rows($this->db_connect_id) : false;}/*** Fetch current row*/function sql_fetchrow($query_id = false){global $cache;if ($query_id === false){{$result = @mysql_affected_rows($this->db_connect_id);$query_id = $this->query_result;return $result;elseif (isset($cache->sql_rowset[$query_id])){{return false;return $cache->sql_fetchrow($query_id);function sql_numfields($query_id = 0)/*** Fetch all rows*/function sql_fetchrowset($query_id = false){{if(!$query_id)$result = false;if ($query_id === false){{if($query_id)if ($query_id !== false){{$result = @mysql_num_fields($query_id);$result = array();while ($row = $this->sql_fetchrow($query_id)){$result[] = $row;}else{return false;return false;}function sql_fieldname($offset, $query_id = 0)/*** Fetch field* if rownum is false, the current row is used, else it is pointing to the row (zero-based)*/function sql_fetchfield($field, $rownum = false, $query_id = false){{if(!$query_id)global $cache;$result = false;if ($query_id === false){{if($query_id)if ($query_id !== false){{$result = @mysql_field_name($query_id, $offset);if ($rownum !== false)return $result;{$this->sql_rowseek($rownum, $query_id);}if (!is_object($query_id) && isset($cache->sql_rowset[$query_id])){return $cache->sql_fetchfield($query_id, $field);}$row = $this->sql_fetchrow($query_id);$result = (isset($row[$field])) ? $row[$field] : false;else{return $result;return false;}function sql_fieldtype($offset, $query_id = 0)/*** Get num fields*/function sql_numfields($query_id = 0){{{{if($query_id){return ($query_id) ? @mysql_num_fields($query_id) : false;$result = @mysql_field_type($query_id, $offset);return $result;}else{return false;}function sql_fetchrow($query_id = 0)/*** Get field name*/function sql_fieldname($offset, $query_id = 0){{{{if($query_id){return ($query_id) ? @mysql_field_name($query_id, $offset) : false;$this->row[$query_id] = @mysql_fetch_array($query_id);return $this->row[$query_id];}else{return false;}function sql_fetchrowset($query_id = 0)/*** Get field type*/function sql_fieldtype($offset, $query_id = 0){{{{if($query_id){return ($query_id) ? @mysql_field_type($query_id, $offset) : false;unset($this->rowset[$query_id]);unset($this->row[$query_id]);while($this->rowset[$query_id] = @mysql_fetch_array($query_id)){$result[] = $this->rowset[$query_id];}return $result;}else{return false;}function sql_fetchfield($field, $rownum = -1, $query_id = 0)/*** Seek to given row number* rownum is zero-based*/function sql_rowseek($rownum, &$query_id){{if(!$query_id)global $cache;if ($query_id === false){{if($query_id)if (isset($cache->sql_rowset[$query_id])){{if($rownum > -1)return $cache->sql_rowseek($rownum, $query_id);{$result = @mysql_result($query_id, $rownum, $field);}else{if(empty($this->row[$query_id]) && empty($this->rowset[$query_id])){if($this->sql_fetchrow()){$result = $this->row[$query_id][$field];}}else{if($this->rowset[$query_id]){$result = $this->rowset[$query_id][0][$field];}else if($this->row[$query_id]){$result = $this->row[$query_id][$field];}}}return $result;else{return ($query_id !== false) ? @mysql_data_seek($query_id, $rownum) : false;return false;}{{$expression = str_replace(array('_', '%'), array("\_", "\%"), $expression);$expression = str_replace(array(chr(0) . "\_", chr(0) . "\%"), array('_', '%'), $expression);return $this->_sql_like_expression('LIKE \'' . $this->sql_escape($expression) . '\'');{{$sql = str_replace('_', ' ', $query) . ' ' . $array['SELECT'] . ' FROM ';{{{{{preg_match('/(' . implode('|', $aliases) . ')\.[^\s]+/U', str_replace(array('(', ')', 'AND', 'OR', ' '), '', $join['ON']), $matches);{{{{{$sql .= $this->_sql_custom_build('FROM', implode(', ', $table_array));{{$sql .= ' LEFT JOIN ' . key($join['FROM']) . ' ' . current($join['FROM']) . ' ON (' . $join['ON'] . ')';{$sql .= ' WHERE ' . $this->_sql_custom_build('WHERE', $array['WHERE']);{{{{$sql_string = $sql_insert ? (' (' . $insert_fields_sql . ') VALUES (' . $insert_values_sql . ')') : $update_sql;function sql_rowseek($rownum, $query_id = 0){/**if(!$query_id)* Build IN or NOT IN sql comparison string, uses <> or = on single element arrays to improve comparison speed** @access public* @param string $field name of the sql column that shall be compared* @param array $array array of values that are allowed (IN) or not allowed (NOT IN)* @param bool $negate true for NOT IN (), false for IN () (default)* @param bool $allow_empty_set If true, allow $array to be empty, this function will return 1=1 or 1=0 then. Default to false.*/function sql_in_set($field, $array, $negate = false, $allow_empty_set = false){if (!sizeof($array)){{$query_id = $this->query_result;if (!$allow_empty_set){// Print the backtrace to help identifying the location of the problematic code$this->sql_error('No values specified for SQL IN comparison');}else{// NOT IN () actually means everything so use a tautologyif ($negate){return '1=1';}// IN () actually means nothing so use a contradictionelse{return '1=0';}}if($query_id)if (!is_array($array)){{$result = @mysql_data_seek($query_id, $rownum);$array = array($array);return $result;{{{return false;return $field . ($negate ? ' NOT IN ' : ' IN ') . '(' . implode(', ', array_map(array($this, 'sql_validate_value'), $array)) . ')';function sql_nextid(){/**if($this->db_connect_id)* Run more than one insert statement.** @param string $table table name to run the statements on* @param array &$sql_ary multi-dimensional array holding the statement data.** @return bool false if no statements were executed.* @access public*/function sql_multi_insert($table, &$sql_ary){if (!sizeof($sql_ary)){{$result = @mysql_insert_id($this->db_connect_id);return false;return $result;{{{$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $sql_ary));{$ary[] = '(' . implode(', ', $values) . ')';$this->sql_query('INSERT INTO ' . $table . ' ' . ' (' . implode(', ', array_keys($sql_ary[0])) . ') VALUES ' . implode(', ', $ary));{{return false;foreach ($sql_ary as $ary){if (!is_array($ary)){return false;}$this->sql_query('INSERT INTO ' . $table . ' ' . $this->sql_build_array('INSERT', $ary));}function sql_freeresult($query_id = 0){/**if(!$query_id)* Free sql result*/function sql_freeresult($query_id = false){global $cache;if ($query_id === false){{if ( $query_id )if (isset($cache->sql_rowset[$query_id])){{unset($this->row[$query_id]);return $cache->sql_freeresult($query_id);unset($this->rowset[$query_id]);}@mysql_free_result($query_id);if (isset($this->open_queries[(int) $query_id])){unset($this->open_queries[(int) $query_id]);return @mysql_free_result($query_id);}return true;return false;}/*** Errors handling*/function sql_error($sql = ''){global $lang;// Set var to retrieve errored status$this->sql_error_triggered = true;$this->sql_error_sql = $sql;$this->sql_error_returned = $this->_sql_error();if (!$this->return_on_error && !defined('IN_INSTALL')){$message = '<b>SQL ERROR [ ' . SQL_LAYER . ' ]</b><br /><br />' . $this->sql_error_returned['message'] . ' [' . $this->sql_error_returned['code'] . ']';// Show complete SQL error and path to administrators only// Additionally show complete error on installation or if extended debug mode is enabled// The DEBUG_EXTRA constant is for development only!if (defined('IN_INSTALL') || (defined('DEBUG_EXTRA') && (DEBUG_EXTRA == true))){$backtrace = get_backtrace();$message .= ($sql) ? '<br /><br /><b>SQL</b><br /><br />' . htmlspecialchars($sql) : '';$message .= ($backtrace) ? '<br /><br /><b>BACKTRACE</b><br />' . $backtrace : '';$message .= '<br />';}else{// If error occurs in initiating the session we need to use a pre-defined language string// This could happen if the connection could not be established for example (then we are not able to grab the default language)if (!isset($lang['SQL_ERROR_OCCURRED'])){$message .= '<br /><br />An sql error occurred while fetching this page. Please contact site administrator if this problem persists.';}else{$message .= '<br /><br />' . $lang['SQL_ERROR_OCCURRED'];}}if ($this->transaction){$this->sql_transaction('rollback');}global $msg_code;$msg_code = CRITICAL_MESSAGE;$message = '<div style="text-align: left;">' . $message . '</div>';if (strlen($message) > 1024){// We need to define $msg_long_text here to circumvent text stripping.global $msg_long_text;$msg_long_text = $message;trigger_error(false, E_USER_NOTICE);}trigger_error($message, E_USER_NOTICE);/*$msg_text = $message;$msg_title = isset($lang['Error']) ? $lang['Error'] : 'Error';message_die($msg_code, $msg_text, $msg_title, __LINE__, __FILE__, $sql);*/elseif ($this->transaction){{return false;$this->sql_transaction('rollback');{{return true;$this->sql_error_triggered = false;$this->sql_error_sql = '';$this->return_on_error = $fail;function sql_error($query_id = 0)/*** SQL Transaction* @access private*/function sql_transaction($status = 'begin'){{$result["message"] = @mysql_error($this->db_connect_id);switch ($status)$result["code"] = @mysql_errno($this->db_connect_id);{case 'begin':// If we are within a transaction we will not open another one, but enclose the current one to not loose data (prevening auto commit)if ($this->transaction){$this->transactions++;return true;}$result = $this->_sql_transaction('begin');{{{$result = $this->_sql_transaction('commit');{$result = $this->_sql_transaction('rollback');} // class sql_db/*** Explain queries*/function sql_report($mode, $query = ''){if (empty($_REQUEST['explain'])){return false;}} // if ... defineif (!$query && ($this->query_hold != '')){$query = $this->query_hold;}{{$mtime = explode(' ', microtime());echo ('<p><b>Page generated in ' . round($totaltime, 4) . " seconds with {$this->num_queries['normal']} queries" . (($this->num_queries['cached']) ? " + {$this->num_queries['cached']} " . (($this->num_queries['cached'] == 1) ? 'query' : 'queries') . ' returning data from cache' : '') . '</b></p>$endtime = explode(' ', microtime());<td class="row1"><textarea style="font-family: \'Courier New\', monospace; width: 99%;" rows="8" cols="160">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td>{$this->sql_report .= 'Elapsed: <b style="color:#224488;">' . sprintf('%.5f', $endtime - $this->curtime) . 's</b> • [Before: ' . sprintf('%.5f', $this->curtime - $this->sql_start_time) . 's | After: ' . sprintf('%.5f', $endtime - $this->sql_start_time) . 's]';if (preg_match('/^(UPDATE|DELETE|REPLACE)/', $query)){{$this->curtime = explode(' ', microtime());{{$this->html_hold .= '<th>' . (($val) ? ucwords(str_replace('_', ' ', $val)) : ' ') . '</th>';{$this->sql_report .= '<td class="row3"><textarea style="font-family: \'Courier New\', monospace; width: 99%;" rows="8" cols="160">' . preg_replace('/\t(AND|OR)(\W)/', "\$1\$2", htmlspecialchars(preg_replace('/[\s]*[\n\r\t]+[\n\r\s\t]*/', "\n", $query))) . '</textarea></td></tr></tbody></table>';$this->sql_report .= 'Before: ' . sprintf('%.5f', $this->curtime - $this->sql_start_time) . 's | After: ' . sprintf('%.5f', $endtime - $this->sql_start_time) . 's | Elapsed [cache]: <b style="color: ' . $color . '">' . sprintf('%.5f', ($time_cache)) . 's</b> | Elapsed [db]: <b>' . sprintf('%.5f', $time_db) . 's</b></p><br /><br />';{{{{{$data = '(' . $data . ')';{{return @mysql_query('BEGIN', $this->db_connect_id);return @mysql_query('COMMIT', $this->db_connect_id);return @mysql_query('ROLLBACK', $this->db_connect_id);{{{{{{if (preg_match('/UPDATE ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)){elseif (preg_match('/DELETE FROM ([a-z0-9_]+).*?WHERE(.*)/s', $query, $m)){if (preg_match('/^SELECT/', $explain_query)){{@mysql_query('SET profiling = 1;', $this->db_connect_id);if ($result = @mysql_query("EXPLAIN $explain_query", $this->db_connect_id)){{$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);{{if ($result = @mysql_query('SHOW PROFILE ALL;', $this->db_connect_id)){{{$row['Source_function'] = str_replace(array('<', '>'), array('<', '>'), $row['Source_function']);{{$html_table = $this->sql_report('add_select_row', $query, $html_table, $row);{@mysql_query('SET profiling = 0;', $this->db_connect_id);$endtime = explode(' ', microtime());{$splittime = explode(' ', microtime());$this->sql_report('record_fromcache', $query, $endtime, $splittime);{{{{{{