source: trunk/include/dblayer/functions_mysql.inc.php @ 5192

Last change on this file since 5192 was 5192, checked in by nikrou, 14 years ago

Fix some sql issues :

  • permalink that use if() syntax
  • add tables themes for other database engines that mysql
File size: 14.5 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based picture gallery                                  |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2009 Piwigo Team                  http://piwigo.org |
6// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
7// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
8// +-----------------------------------------------------------------------+
9// | This program is free software; you can redistribute it and/or modify  |
10// | it under the terms of the GNU General Public License as published by  |
11// | the Free Software Foundation                                          |
12// |                                                                       |
13// | This program is distributed in the hope that it will be useful, but   |
14// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
15// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
16// | General Public License for more details.                              |
17// |                                                                       |
18// | You should have received a copy of the GNU General Public License     |
19// | along with this program; if not, write to the Free Software           |
20// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
21// | USA.                                                                  |
22// +-----------------------------------------------------------------------+
23
24define('DB_ENGINE', 'MySQL');
25
26define('DB_REGEX_OPERATOR', 'REGEXP');
27define('DB_RANDOM_FUNCTION', 'RAND');
28
29/**
30 *
31 * simple functions
32 *
33 */
34
35function pwg_db_connect($host, $user, $password, $database)
36{ 
37  $link = mysql_connect($host, $user, $password) or my_error('mysql_connect', false);
38  mysql_select_db($database, $link) or my_error('mysql_select_db', false);
39
40  return $link;
41}
42
43function pwg_db_check_charset() 
44{
45  defined('PWG_CHARSET') and defined('DB_CHARSET')
46    or fatal_error('PWG_CHARSET and/or DB_CHARSET is not defined');
47  if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') )
48  {
49    if (DB_CHARSET!='')
50    {
51      pwg_query('SET NAMES "'.DB_CHARSET.'"');
52    }
53  }
54  elseif ( strtolower(PWG_CHARSET)!='iso-8859-1' )
55  {
56    fatal_error('PWG supports only iso-8859-1 charset on MySql version '.mysql_get_server_info());
57  }
58}
59
60function pwg_get_db_version() 
61{
62  list($mysql_version) = pwg_db_fetch_row(pwg_query('SELECT VERSION();'));
63 
64  return $mysql_version;
65}
66
67function pwg_query($query)
68{
69  global $conf,$page,$debug,$t2;
70
71  $start = get_moment();
72  ($result = mysql_query($query)) or my_error($query, $conf['die_on_sql_error']);
73
74  $time = get_moment() - $start;
75
76  if (!isset($page['count_queries']))
77  {
78    $page['count_queries'] = 0;
79    $page['queries_time'] = 0;
80  }
81
82  $page['count_queries']++;
83  $page['queries_time']+= $time;
84
85  if ($conf['show_queries'])
86  {
87    $output = '';
88    $output.= '<pre>['.$page['count_queries'].'] ';
89    $output.= "\n".$query;
90    $output.= "\n".'(this query time : ';
91    $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
92    $output.= "\n".'(total SQL time  : ';
93    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
94    $output.= "\n".'(total time      : ';
95    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
96    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
97    {
98      $output.= "\n".'(num rows        : ';
99      $output.= mysql_num_rows($result).' )';
100    }
101    elseif ( $result!=null
102      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
103    {
104      $output.= "\n".'(affected rows   : ';
105      $output.= mysql_affected_rows().' )';
106    }
107    $output.= "</pre>\n";
108
109    $debug .= $output;
110  }
111
112  return $result;
113}
114
115function pwg_db_nextval($column, $table)
116{
117  $query = '
118SELECT IF(MAX('.$column.')+1 IS NULL, 1, MAX('.$column.')+1)
119  FROM '.$table;
120  list($next) = pwg_db_fetch_row(pwg_query($query));
121
122  return $next;
123}
124
125function pwg_db_changes($result) 
126{
127  return mysql_affected_rows();
128}
129
130function pwg_db_num_rows($result) 
131{
132  return mysql_num_rows($result);
133}
134
135function pwg_db_fetch_assoc($result)
136{
137  return mysql_fetch_assoc($result);
138}
139
140function pwg_db_fetch_row($result)
141{
142  return mysql_fetch_row($result);
143}
144
145function pwg_db_fetch_object($result)
146{
147  return mysql_fetch_object($result);
148}
149
150function pwg_db_free_result($result) 
151{
152  return mysql_free_result($result);
153}
154
155function pwg_db_real_escape_string($s)
156{
157  return mysql_real_escape_string($s);
158}
159
160function pwg_db_insert_id($table=null, $column='id')
161{
162  return mysql_insert_id();
163}
164
165/**
166 *
167 * complex functions
168 *
169 */
170
171/**
172 * creates an array based on a query, this function is a very common pattern
173 * used here
174 *
175 * @param string $query
176 * @param string $fieldname
177 * @return array
178 */
179function array_from_query($query, $fieldname)
180{
181  $array = array();
182
183  $result = pwg_query($query);
184  while ($row = mysql_fetch_assoc($result))
185  {
186    array_push($array, $row[$fieldname]);
187  }
188
189  return $array;
190}
191
192define('MASS_UPDATES_SKIP_EMPTY', 1);
193/**
194 * updates multiple lines in a table
195 *
196 * @param string table_name
197 * @param array dbfields
198 * @param array datas
199 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
200 * @return void
201 */
202function mass_updates($tablename, $dbfields, $datas, $flags=0)
203{
204  if (count($datas) == 0)
205    return;
206  // depending on the MySQL version, we use the multi table update or N update queries
207  if (count($datas) < 10 or version_compare(mysql_get_server_info(), '4.0.4') < 0)
208  { // MySQL is prior to version 4.0.4, multi table update feature is not available
209    foreach ($datas as $data)
210    {
211      $query = '
212UPDATE '.$tablename.'
213  SET ';
214      $is_first = true;
215      foreach ($dbfields['update'] as $key)
216      {
217        $separator = $is_first ? '' : ",\n    ";
218
219        if (isset($data[$key]) and $data[$key] != '')
220        {
221          $query.= $separator.$key.' = \''.$data[$key].'\'';
222        }
223        else
224        {
225          if ($flags & MASS_UPDATES_SKIP_EMPTY )
226            continue; // next field
227          $query.= "$separator$key = NULL";
228        }
229        $is_first = false;
230      }
231      if (!$is_first)
232      {// only if one field at least updated
233        $query.= '
234  WHERE ';
235        $is_first = true;
236        foreach ($dbfields['primary'] as $key)
237        {
238          if (!$is_first)
239          {
240            $query.= ' AND ';
241          }
242          if ( isset($data[$key]) )
243          {
244            $query.= $key.' = \''.$data[$key].'\'';
245          }
246          else
247          {
248            $query.= $key.' IS NULL';
249          }
250          $is_first = false;
251        }
252        pwg_query($query);
253      }
254    } // foreach update
255  } // if mysql_ver or count<X
256  else
257  {
258    // creation of the temporary table
259    $query = '
260SHOW FULL COLUMNS FROM '.$tablename;
261    $result = pwg_query($query);
262    $columns = array();
263    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
264    while ($row = pwg_db_fetch_assoc($result))
265    {
266      if (in_array($row['Field'], $all_fields))
267      {
268        $column = $row['Field'];
269        $column.= ' '.$row['Type'];
270
271        $nullable = true;
272        if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO')
273        {
274          $column.= ' NOT NULL';
275          $nullable = false;
276        }
277        if (isset($row['Default']))
278        {
279          $column.= " default '".$row['Default']."'";
280        }
281        elseif ($nullable)
282        {
283          $column.= " default NULL";
284        }
285        if (isset($row['Collation']) and $row['Collation'] != 'NULL')
286        {
287          $column.= " collate '".$row['Collation']."'";
288        }
289        array_push($columns, $column);
290      }
291    }
292
293    $temporary_tablename = $tablename.'_'.micro_seconds();
294
295    $query = '
296CREATE TABLE '.$temporary_tablename.'
297(
298  '.implode(",\n  ", $columns).',
299  UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).')
300)';
301
302    pwg_query($query);
303    mass_inserts($temporary_tablename, $all_fields, $datas);
304    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
305      $func_set = create_function('$s', 'return "t1.$s = IFNULL(t2.$s, t1.$s)";');
306    else
307      $func_set = create_function('$s', 'return "t1.$s = t2.$s";');
308
309    // update of images table by joining with temporary table
310    $query = '
311UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
312  SET '.
313      implode(
314        "\n    , ",
315        array_map($func_set,$dbfields['update'])
316        ).'
317  WHERE '.
318      implode(
319        "\n    AND ",
320        array_map(
321          create_function('$s', 'return "t1.$s = t2.$s";'),
322          $dbfields['primary']
323          )
324        );
325    pwg_query($query);
326    $query = '
327DROP TABLE '.$temporary_tablename;
328    pwg_query($query);
329  }
330}
331
332
333/**
334 * inserts multiple lines in a table
335 *
336 * @param string table_name
337 * @param array dbfields
338 * @param array inserts
339 * @return void
340 */
341function mass_inserts($table_name, $dbfields, $datas)
342{
343  if (count($datas) != 0)
344  {
345    $first = true;
346
347    $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\'';
348    list(, $packet_size) = pwg_db_fetch_row(pwg_query($query));
349    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
350    $query = '';
351
352    foreach ($datas as $insert)
353    {
354      if (strlen($query) >= $packet_size)
355      {
356        pwg_query($query);
357        $first = true;
358      }
359
360      if ($first)
361      {
362        $query = '
363INSERT INTO '.$table_name.'
364  ('.implode(',', $dbfields).')
365  VALUES';
366        $first = false;
367      }
368      else
369      {
370        $query .= '
371  , ';
372      }
373
374      $query .= '(';
375      foreach ($dbfields as $field_id => $dbfield)
376      {
377        if ($field_id > 0)
378        {
379          $query .= ',';
380        }
381
382        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
383        {
384          $query .= 'NULL';
385        }
386        else
387        {
388          $query .= "'".$insert[$dbfield]."'";
389        }
390      }
391      $query .= ')';
392    }
393    pwg_query($query);
394  }
395}
396
397/**
398 * Do maintenance on all PWG tables
399 *
400 * @return none
401 */
402function do_maintenance_all_tables()
403{
404  global $prefixeTable, $page;
405
406  $all_tables = array();
407
408  // List all tables
409  $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\'';
410  $result = pwg_query($query);
411  while ($row = pwg_db_fetch_row($result))
412  {
413    array_push($all_tables, $row[0]);
414  }
415
416  // Repair all tables
417  $query = 'REPAIR TABLE '.implode(', ', $all_tables);
418  $mysql_rc = pwg_query($query);
419
420  // Re-Order all tables
421  foreach ($all_tables as $table_name)
422  {
423    $all_primary_key = array();
424
425    $query = 'DESC '.$table_name.';';
426    $result = pwg_query($query);
427    while ($row = pwg_db_fetch_assoc($result))
428    {
429      if ($row['Key'] == 'PRI')
430      {
431        array_push($all_primary_key, $row['Field']);
432      }
433    }
434
435    if (count($all_primary_key) != 0)
436    {
437      $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';';
438      $mysql_rc = $mysql_rc && pwg_query($query);
439    }
440  }
441
442  // Optimize all tables
443  $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables);
444  $mysql_rc = $mysql_rc && pwg_query($query);
445  if ($mysql_rc)
446  {
447    array_push(
448          $page['infos'],
449          l10n('All optimizations have been successfully completed.')
450          );
451  }
452  else
453  {
454    array_push(
455          $page['errors'],
456          l10n('Optimizations have been completed with some errors.')
457          );
458  }
459}
460
461function pwg_db_concat($array)
462{
463  $string = implode($array, ',');
464  return 'CONCAT('. $string.')';
465}
466
467function pwg_db_concat_ws($array, $separator)
468{
469  $string = implode($array, ',');
470  return 'CONCAT_WS(\''.$separator.'\','. $string.')';
471}
472
473function pwg_db_cast_to_text($string)
474{
475  return 'CAST('.$string.' AS CHAR)';
476}
477
478/**
479 * returns an array containing the possible values of an enum field
480 *
481 * @param string tablename
482 * @param string fieldname
483 */
484function get_enums($table, $field)
485{
486  // retrieving the properties of the table. Each line represents a field :
487  // columns are 'Field', 'Type'
488  $result = pwg_query('desc '.$table);
489  while ($row = pwg_db_fetch_assoc($result))
490  {
491    // we are only interested in the the field given in parameter for the
492    // function
493    if ($row['Field'] == $field)
494    {
495      // retrieving possible values of the enum field
496      // enum('blue','green','black')
497      $options = explode(',', substr($row['Type'], 5, -1));
498      foreach ($options as $i => $option)
499      {
500        $options[$i] = str_replace("'", '',$option);
501      }
502    }
503  }
504  pwg_db_free_result($result);
505  return $options;
506}
507
508// get_boolean transforms a string to a boolean value. If the string is
509// "false" (case insensitive), then the boolean value false is returned. In
510// any other case, true is returned.
511function get_boolean( $string )
512{
513  $boolean = true;
514  if ( 'false' == strtolower($string) )
515  {
516    $boolean = false;
517  }
518  return $boolean;
519}
520
521/**
522 * returns boolean string 'true' or 'false' if the given var is boolean
523 *
524 * @param mixed $var
525 * @return mixed
526 */
527function boolean_to_string($var)
528{
529  if (is_bool($var))
530  {
531    return $var ? 'true' : 'false';
532  }
533  else
534  {
535    return $var;
536  }
537}
538
539/**
540 *
541 * interval and date functions
542 *
543 */
544
545
546function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
547{
548  if ($date!='CURRENT_DATE')
549  {
550    $date = '\''.$date.'\'';
551  }
552
553  return 'SUBDATE('.$date.',INTERVAL '.$period.' DAY)';
554}
555
556function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
557{
558  $query = '
559SELECT '.pwg_db_get_recent_period_expression($period);
560  list($d) = pwg_db_fetch_row(pwg_query($query));
561
562  return $d;
563}
564
565function pwg_db_get_date_YYYYMM($date)
566{
567  return 'DATE_FORMAT('.$date.', \'%Y%m\')';
568}
569
570function pwg_db_get_date_MMDD($date)
571{
572  return 'DATE_FORMAT('.$date.', \'%m%d\')';
573}
574
575function pwg_db_get_year($date)
576{
577  return 'YEAR('.$date.')';
578}
579
580function pwg_db_get_month($date)
581{
582  return 'MONTH('.$date.')';
583}
584
585function pwg_db_get_week($date, $mode=null)
586{
587  if ($mode)
588  {
589    return 'WEEK('.$date.', '.$mode.')';
590  }
591  else
592  {
593    return 'WEEK('.$date.')';
594  }
595}
596
597function pwg_db_get_dayofmonth($date)
598{
599  return 'DAYOFMONTH('.$date.')';
600}
601
602function pwg_db_get_dayofweek($date)
603{
604  return 'DAYOFWEEK('.$date.')';
605}
606
607function pwg_db_get_weekday($date)
608{
609  return 'WEEKDAY('.$date.')';
610}
611
612// my_error returns (or send to standard output) the message concerning the
613// error occured for the last mysql query.
614function my_error($header, $die)
615{
616  $error = "[mysql error ".mysql_errno().'] '.mysql_error()."\n";
617  $error .= $header;
618
619  if ($die)
620  {
621    fatal_error($error);
622  }
623  echo("<pre>");
624  trigger_error($error, E_USER_WARNING);
625  echo("</pre>");
626}
627
628?>
Note: See TracBrowser for help on using the repository browser.