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

Last change on this file since 21088 was 21088, checked in by mistic100, 11 years ago

feature:65 add pwg_db_errno and pwg_db_error

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