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

Revision 4781, 14.3 KB checked in by nikrou, 10 years ago (diff)

Feature 511 : add support for sqlite database engine

Using session_write_close function when session handler use database because write is called after object destruction.

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