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

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

feature:65 add pwg_db_errno and pwg_db_error

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