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

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

feature:65 add fetch_array SQL functions

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