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

Last change on this file since 18573 was 18573, checked in by rvelices, 12 years ago

batch manager - remove unused code, less sql queries and avoid 4 calls to same display_select function

File size: 16.8 KB
Line 
1<?php
2// +-----------------------------------------------------------------------+
3// | Piwigo - a PHP based photo gallery                                    |
4// +-----------------------------------------------------------------------+
5// | Copyright(C) 2008-2012 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');
25define('REQUIRED_MYSQL_VERSION', '5.0.0');
26
27define('DB_REGEX_OPERATOR', 'REGEXP');
28define('DB_RANDOM_FUNCTION', 'RAND');
29
30/**
31 *
32 * simple functions
33 *
34 */
35
36function pwg_db_connect($host, $user, $password, $database)
37{ 
38  $link = @mysql_connect($host, $user, $password);
39  if (!$link)
40  {
41    throw new Exception("Can't connect to server");
42  }
43  if (mysql_select_db($database, $link))
44  {
45    return $link;
46  }
47  else
48  {
49    throw new Exception('Connection to server succeed, but it was impossible to connect to database');
50  }
51}
52
53function pwg_db_check_charset() 
54{
55  $db_charset = 'utf8';
56  if (defined('DB_CHARSET') and DB_CHARSET != '')
57  {
58    $db_charset = DB_CHARSET;
59  }
60  pwg_query('SET NAMES "'.$db_charset.'"');
61}
62
63function pwg_db_check_version()
64{
65  $current_mysql = pwg_get_db_version();
66  if (version_compare($current_mysql, REQUIRED_MYSQL_VERSION, '<'))
67  {
68    fatal_error(
69      sprintf(
70        'your MySQL version is too old, you have "%s" and you need at least "%s"',
71        $current_mysql,
72        REQUIRED_MYSQL_VERSION
73        )
74      );
75  }
76}
77
78function pwg_get_db_version() 
79{
80  return mysql_get_server_info();
81}
82
83function pwg_query($query)
84{
85  global $conf,$page,$debug,$t2;
86
87  $start = microtime(true);
88  ($result = mysql_query($query)) or my_error($query, $conf['die_on_sql_error']);
89
90  $time = microtime(true) - $start;
91
92  if (!isset($page['count_queries']))
93  {
94    $page['count_queries'] = 0;
95    $page['queries_time'] = 0;
96  }
97
98  $page['count_queries']++;
99  $page['queries_time']+= $time;
100
101  if ($conf['show_queries'])
102  {
103    $output = '';
104    $output.= '<pre>['.$page['count_queries'].'] ';
105    $output.= "\n".$query;
106    $output.= "\n".'(this query time : ';
107    $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
108    $output.= "\n".'(total SQL time  : ';
109    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
110    $output.= "\n".'(total time      : ';
111    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
112    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
113    {
114      $output.= "\n".'(num rows        : ';
115      $output.= mysql_num_rows($result).' )';
116    }
117    elseif ( $result!=null
118      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
119    {
120      $output.= "\n".'(affected rows   : ';
121      $output.= mysql_affected_rows().' )';
122    }
123    $output.= "</pre>\n";
124
125    $debug .= $output;
126  }
127
128  return $result;
129}
130
131function pwg_db_nextval($column, $table)
132{
133  $query = '
134SELECT IF(MAX('.$column.')+1 IS NULL, 1, MAX('.$column.')+1)
135  FROM '.$table;
136  list($next) = pwg_db_fetch_row(pwg_query($query));
137
138  return $next;
139}
140
141function pwg_db_changes($result) 
142{
143  return mysql_affected_rows();
144}
145
146function pwg_db_num_rows($result) 
147{
148  return mysql_num_rows($result);
149}
150
151function pwg_db_fetch_assoc($result)
152{
153  return mysql_fetch_assoc($result);
154}
155
156function pwg_db_fetch_row($result)
157{
158  return mysql_fetch_row($result);
159}
160
161function pwg_db_fetch_object($result)
162{
163  return mysql_fetch_object($result);
164}
165
166function pwg_db_free_result($result) 
167{
168  return mysql_free_result($result);
169}
170
171function pwg_db_real_escape_string($s)
172{
173  return mysql_real_escape_string($s);
174}
175
176function pwg_db_insert_id($table=null, $column='id')
177{
178  return mysql_insert_id();
179}
180
181/**
182 *
183 * complex functions
184 *
185 */
186
187/**
188 * creates an array based on a query, this function is a very common pattern
189 * used here
190 *
191 * @param string $query
192 * @param string $fieldname optional
193 * @return array
194 */
195function array_from_query($query, $fieldname=false)
196{
197  $array = array();
198
199  $result = pwg_query($query);
200  if (false === $fieldname)
201  {
202    while ($row = mysql_fetch_assoc($result))
203    {
204      $array[] = $row;     
205    }
206  }
207  else
208  {
209    while ($row = mysql_fetch_assoc($result))
210    {
211      $array[] = $row[$fieldname];
212    }
213  }
214  return $array;
215}
216
217define('MASS_UPDATES_SKIP_EMPTY', 1);
218/**
219 * updates multiple lines in a table
220 *
221 * @param string table_name
222 * @param array dbfields
223 * @param array datas
224 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
225 * @return void
226 */
227function mass_updates($tablename, $dbfields, $datas, $flags=0)
228{
229  if (count($datas) == 0)
230    return;
231 
232  // depending on the MySQL version, we use the multi table update or N update queries
233  if (count($datas) < 10)
234  {
235    foreach ($datas as $data)
236    {
237      $query = '
238UPDATE '.$tablename.'
239  SET ';
240      $is_first = true;
241      foreach ($dbfields['update'] as $key)
242      {
243        $separator = $is_first ? '' : ",\n    ";
244
245        if (isset($data[$key]) and $data[$key] != '')
246        {
247          $query.= $separator.$key.' = \''.$data[$key].'\'';
248        }
249        else
250        {
251          if ( $flags & MASS_UPDATES_SKIP_EMPTY )
252            continue; // next field
253          $query.= "$separator$key = NULL";
254        }
255        $is_first = false;
256      }
257      if (!$is_first)
258      {// only if one field at least updated
259        $query.= '
260  WHERE ';
261        $is_first = true;
262        foreach ($dbfields['primary'] as $key)
263        {
264          if (!$is_first)
265          {
266            $query.= ' AND ';
267          }
268          if ( isset($data[$key]) )
269          {
270            $query.= $key.' = \''.$data[$key].'\'';
271          }
272          else
273          {
274            $query.= $key.' IS NULL';
275          }
276          $is_first = false;
277        }
278        pwg_query($query);
279      }
280    } // foreach update
281  } // if mysql_ver or count<X
282  else
283  {
284    // creation of the temporary table
285    $query = '
286SHOW FULL COLUMNS FROM '.$tablename;
287    $result = pwg_query($query);
288    $columns = array();
289    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
290    while ($row = pwg_db_fetch_assoc($result))
291    {
292      if (in_array($row['Field'], $all_fields))
293      {
294        $column = $row['Field'];
295        $column.= ' '.$row['Type'];
296
297        $nullable = true;
298        if (!isset($row['Null']) or $row['Null'] == '' or $row['Null']=='NO')
299        {
300          $column.= ' NOT NULL';
301          $nullable = false;
302        }
303        if (isset($row['Default']))
304        {
305          $column.= " default '".$row['Default']."'";
306        }
307        elseif ($nullable)
308        {
309          $column.= " default NULL";
310        }
311        if (isset($row['Collation']) and $row['Collation'] != 'NULL')
312        {
313          $column.= " collate '".$row['Collation']."'";
314        }
315        array_push($columns, $column);
316      }
317    }
318
319    $temporary_tablename = $tablename.'_'.micro_seconds();
320
321    $query = '
322CREATE TABLE '.$temporary_tablename.'
323(
324  '.implode(",\n  ", $columns).',
325  UNIQUE KEY the_key ('.implode(',', $dbfields['primary']).')
326)';
327
328    pwg_query($query);
329    mass_inserts($temporary_tablename, $all_fields, $datas);
330    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
331      $func_set = create_function('$s', 'return "t1.$s = IFNULL(t2.$s, t1.$s)";');
332    else
333      $func_set = create_function('$s', 'return "t1.$s = t2.$s";');
334
335    // update of images table by joining with temporary table
336    $query = '
337UPDATE '.$tablename.' AS t1, '.$temporary_tablename.' AS t2
338  SET '.
339      implode(
340        "\n    , ",
341        array_map($func_set,$dbfields['update'])
342        ).'
343  WHERE '.
344      implode(
345        "\n    AND ",
346        array_map(
347          create_function('$s', 'return "t1.$s = t2.$s";'),
348          $dbfields['primary']
349          )
350        );
351    pwg_query($query);
352    $query = '
353DROP TABLE '.$temporary_tablename;
354    pwg_query($query);
355  }
356}
357
358/**
359 * updates one line in a table
360 *
361 * @param string table_name
362 * @param array set_fields
363 * @param array where_fields
364 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
365 * @return void
366 */
367function single_update($tablename, $set_fields, $where_fields, $flags=0)
368{
369  if (count($set_fields) == 0)
370  {
371    return;
372  }
373
374  $query = '
375UPDATE '.$tablename.'
376  SET ';
377  $is_first = true;
378  foreach ($set_fields as $key => $value)
379  {
380    $separator = $is_first ? '' : ",\n    ";
381
382    if (isset($value) and $value !== '')
383    {
384      $query.= $separator.$key.' = \''.$value.'\'';
385    }
386    else
387    {
388      if ( $flags & MASS_UPDATES_SKIP_EMPTY )
389        continue; // next field
390      $query.= "$separator$key = NULL";
391    }
392    $is_first = false;
393  }
394  if (!$is_first)
395  {// only if one field at least updated
396    $query.= '
397  WHERE ';
398    $is_first = true;
399    foreach ($where_fields as $key => $value)
400    {
401      if (!$is_first)
402      {
403        $query.= ' AND ';
404      }
405      if ( isset($value) )
406      {
407        $query.= $key.' = \''.$value.'\'';
408      }
409      else
410      {
411        $query.= $key.' IS NULL';
412      }
413      $is_first = false;
414    }
415    pwg_query($query);
416  }
417}
418
419
420/**
421 * inserts multiple lines in a table
422 *
423 * @param string table_name
424 * @param array dbfields
425 * @param array inserts
426 * @return void
427 */
428function mass_inserts($table_name, $dbfields, $datas, $options=array())
429{
430  $ignore = '';
431  if (isset($options['ignore']) and $options['ignore'])
432  {
433    $ignore = 'IGNORE';
434  }
435 
436  if (count($datas) != 0)
437  {
438    $first = true;
439
440    $query = 'SHOW VARIABLES LIKE \'max_allowed_packet\'';
441    list(, $packet_size) = pwg_db_fetch_row(pwg_query($query));
442    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
443    $query = '';
444
445    foreach ($datas as $insert)
446    {
447      if (strlen($query) >= $packet_size)
448      {
449        pwg_query($query);
450        $first = true;
451      }
452
453      if ($first)
454      {
455        $query = '
456INSERT '.$ignore.' INTO '.$table_name.'
457  ('.implode(',', $dbfields).')
458  VALUES';
459        $first = false;
460      }
461      else
462      {
463        $query .= '
464  , ';
465      }
466
467      $query .= '(';
468      foreach ($dbfields as $field_id => $dbfield)
469      {
470        if ($field_id > 0)
471        {
472          $query .= ',';
473        }
474
475        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
476        {
477          $query .= 'NULL';
478        }
479        else
480        {
481          $query .= "'".$insert[$dbfield]."'";
482        }
483      }
484      $query .= ')';
485    }
486    pwg_query($query);
487  }
488}
489
490/**
491 * inserts one line in a table
492 *
493 * @param string table_name
494 * @param array dbfields
495 * @param array insert
496 * @return void
497 */
498function single_insert($table_name, $data)
499{
500  if (count($data) != 0)
501  {
502    $query = '
503INSERT INTO '.$table_name.'
504  ('.implode(',', array_keys($data)).')
505  VALUES';
506
507    $query .= '(';
508    $is_first = true;
509    foreach ($data as $key => $value)
510    {
511      if (!$is_first)
512      {
513        $query .= ',';
514      }
515      else
516      {
517        $is_first = false;
518      }
519     
520      if ($value === '')
521      {
522        $query .= 'NULL';
523      }
524      else
525      {
526        $query .= "'".$value."'";
527      }
528    }
529    $query .= ')';
530   
531    pwg_query($query);
532  }
533}
534
535/**
536 * Do maintenance on all PWG tables
537 *
538 * @return none
539 */
540function do_maintenance_all_tables()
541{
542  global $prefixeTable, $page;
543
544  $all_tables = array();
545
546  // List all tables
547  $query = 'SHOW TABLES LIKE \''.$prefixeTable.'%\'';
548  $result = pwg_query($query);
549  while ($row = pwg_db_fetch_row($result))
550  {
551    array_push($all_tables, $row[0]);
552  }
553
554  // Repair all tables
555  $query = 'REPAIR TABLE '.implode(', ', $all_tables);
556  $mysql_rc = pwg_query($query);
557
558  // Re-Order all tables
559  foreach ($all_tables as $table_name)
560  {
561    $all_primary_key = array();
562
563    $query = 'DESC '.$table_name.';';
564    $result = pwg_query($query);
565    while ($row = pwg_db_fetch_assoc($result))
566    {
567      if ($row['Key'] == 'PRI')
568      {
569        array_push($all_primary_key, $row['Field']);
570      }
571    }
572
573    if (count($all_primary_key) != 0)
574    {
575      $query = 'ALTER TABLE '.$table_name.' ORDER BY '.implode(', ', $all_primary_key).';';
576      $mysql_rc = $mysql_rc && pwg_query($query);
577    }
578  }
579
580  // Optimize all tables
581  $query = 'OPTIMIZE TABLE '.implode(', ', $all_tables);
582  $mysql_rc = $mysql_rc && pwg_query($query);
583  if ($mysql_rc)
584  {
585    array_push(
586          $page['infos'],
587          l10n('All optimizations have been successfully completed.')
588          );
589  }
590  else
591  {
592    array_push(
593          $page['errors'],
594          l10n('Optimizations have been completed with some errors.')
595          );
596  }
597}
598
599function pwg_db_concat($array)
600{
601  $string = implode($array, ',');
602  return 'CONCAT('. $string.')';
603}
604
605function pwg_db_concat_ws($array, $separator)
606{
607  $string = implode($array, ',');
608  return 'CONCAT_WS(\''.$separator.'\','. $string.')';
609}
610
611function pwg_db_cast_to_text($string)
612{
613  return $string;
614}
615
616/**
617 * returns an array containing the possible values of an enum field
618 *
619 * @param string tablename
620 * @param string fieldname
621 */
622function get_enums($table, $field)
623{
624  // retrieving the properties of the table. Each line represents a field :
625  // columns are 'Field', 'Type'
626  $result = pwg_query('desc '.$table);
627  while ($row = pwg_db_fetch_assoc($result))
628  {
629    // we are only interested in the the field given in parameter for the
630    // function
631    if ($row['Field'] == $field)
632    {
633      // retrieving possible values of the enum field
634      // enum('blue','green','black')
635      $options = explode(',', substr($row['Type'], 5, -1));
636      foreach ($options as $i => $option)
637      {
638        $options[$i] = str_replace("'", '',$option);
639      }
640    }
641  }
642  pwg_db_free_result($result);
643  return $options;
644}
645
646/**
647 * Smartly checks if a variable is equivalent to true or false
648 *
649 * @param mixed input
650 * @return bool
651 */
652function get_boolean($input)
653{
654  if ('false' === strtolower($input))
655  {
656    return false;
657  }
658
659  return (bool)$input;
660}
661
662/**
663 * returns boolean string 'true' or 'false' if the given var is boolean
664 *
665 * @param mixed $var
666 * @return mixed
667 */
668function boolean_to_string($var)
669{
670  if (is_bool($var))
671  {
672    return $var ? 'true' : 'false';
673  }
674  else
675  {
676    return $var;
677  }
678}
679
680/**
681 *
682 * interval and date functions
683 *
684 */
685
686function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
687{
688  if ($date!='CURRENT_DATE')
689  {
690    $date = '\''.$date.'\'';
691  }
692
693  return 'SUBDATE('.$date.',INTERVAL '.$period.' DAY)';
694}
695
696function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
697{
698  $query = '
699SELECT '.pwg_db_get_recent_period_expression($period);
700  list($d) = pwg_db_fetch_row(pwg_query($query));
701
702  return $d;
703}
704
705function pwg_db_get_flood_period_expression($seconds)
706{
707  return 'SUBDATE(now(), INTERVAL '.$seconds.' SECOND)';
708}
709
710function pwg_db_get_hour($date) 
711{
712  return 'hour('.$date.')';
713}
714
715function pwg_db_get_date_YYYYMM($date)
716{
717  return 'DATE_FORMAT('.$date.', \'%Y%m\')';
718}
719
720function pwg_db_get_date_MMDD($date)
721{
722  return 'DATE_FORMAT('.$date.', \'%m%d\')';
723}
724
725function pwg_db_get_year($date)
726{
727  return 'YEAR('.$date.')';
728}
729
730function pwg_db_get_month($date)
731{
732  return 'MONTH('.$date.')';
733}
734
735function pwg_db_get_week($date, $mode=null)
736{
737  if ($mode)
738  {
739    return 'WEEK('.$date.', '.$mode.')';
740  }
741  else
742  {
743    return 'WEEK('.$date.')';
744  }
745}
746
747function pwg_db_get_dayofmonth($date)
748{
749  return 'DAYOFMONTH('.$date.')';
750}
751
752function pwg_db_get_dayofweek($date)
753{
754  return 'DAYOFWEEK('.$date.')';
755}
756
757function pwg_db_get_weekday($date)
758{
759  return 'WEEKDAY('.$date.')';
760}
761
762function pwg_db_date_to_ts($date) 
763{
764  return 'UNIX_TIMESTAMP('.$date.')';
765}
766
767// my_error returns (or send to standard output) the message concerning the
768// error occured for the last mysql query.
769function my_error($header, $die)
770{
771  $error = "[mysql error ".mysql_errno().'] '.mysql_error()."\n";
772  $error .= $header;
773
774  if ($die)
775  {
776    fatal_error($error);
777  }
778  echo("<pre>");
779  trigger_error($error, E_USER_WARNING);
780  echo("</pre>");
781}
782
783?>
Note: See TracBrowser for help on using the repository browser.