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

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

Feature 1255 :
only one function
use exceptions to deal with differents possible errors

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