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

Revision 4781, 11.9 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('REQUIRED_PGSQL_VERSION', '8.0');
25define('DB_ENGINE', 'PostgreSQL');
26
27define('DB_REGEX_OPERATOR', '~');
28define('DB_RANDOM_FUNCTION', 'RANDOM');
29
30/**
31 *
32 * simple functions
33 *
34 */
35
36function pwg_db_connect($host, $user, $password, $database)
37{
38  $connection_string = '';
39  if (strpos($host,':') !== false) 
40  {
41    list($host, $port) = explode(':', $host);
42  }
43  $connection_string = sprintf('host=%s', $host);
44  if (!empty($port))
45  {
46    $connection_string .= sprintf(' port=%d', $port);
47  }
48  $connection_string .= sprintf(' user=%s password=%s dbname=%s', 
49                                $user, 
50                                $password,
51                                $database);
52  $link = pg_connect($connection_string) or my_error('pg_connect', true); 
53
54  return $link;
55}
56
57function pwg_db_check_charset() 
58{
59  return true;
60}
61
62function pwg_get_db_version() 
63{
64  list($pg_version) = pwg_db_fetch_row(pwg_query('SHOW SERVER_VERSION;'));
65 
66  return $pg_version;
67}
68
69function pwg_query($query)
70{
71  global $conf,$page,$debug,$t2;
72
73  $start = get_moment();
74  ($result = pg_query($query)) or die($query."\n<br>".pg_last_error());
75
76  $time = get_moment() - $start;
77
78  if (!isset($page['count_queries']))
79  {
80    $page['count_queries'] = 0;
81    $page['queries_time'] = 0;
82  }
83
84  $page['count_queries']++;
85  $page['queries_time']+= $time;
86
87  if ($conf['show_queries'])
88  {
89    $output = '';
90    $output.= '<pre>['.$page['count_queries'].'] ';
91    $output.= "\n".$query;
92    $output.= "\n".'(this query time : ';
93    $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>';
94    $output.= "\n".'(total SQL time  : ';
95    $output.= number_format($page['queries_time'], 3, '.', ' ').' s)';
96    $output.= "\n".'(total time      : ';
97    $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)';
98    if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) )
99    {
100      $output.= "\n".'(num rows        : ';
101      $output.= pwg_db_num_rows($result).' )';
102    }
103    elseif ( $result!=null
104      and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) )
105    {
106      $output.= "\n".'(affected rows   : ';
107      $output.= pwg_db_changes($result).' )';
108    }
109    $output.= "</pre>\n";
110
111    $debug .= $output;
112  }
113
114  return $result;
115}
116
117function pwg_db_nextval($column, $table)
118{
119  $query = '
120SELECT nextval(\''.$table.'_'.$column.'_seq\')';
121  list($next) = pwg_db_fetch_row(pwg_query($query));
122
123  return $next;
124}
125
126/**
127 *
128 * complex functions
129 *
130 */
131
132function pwg_db_changes($result) 
133{
134  return pg_affected_rows($result);
135}
136
137function pwg_db_num_rows($result) 
138{
139  return pg_num_rows($result);
140}
141
142function pwg_db_fetch_assoc($result)
143{
144  return pg_fetch_assoc($result);
145}
146
147function pwg_db_fetch_row($result)
148{
149  return pg_fetch_row($result);
150}
151
152function pwg_db_fetch_object($result)
153{
154  return pg_fetch_object($result);
155}
156
157function pwg_db_free_result($result) 
158{
159  return pg_free_result($result);
160}
161
162function pwg_db_real_escape_string($s)
163{
164  return pg_escape_string($s);
165}
166
167function pwg_db_insert_id()
168{
169  // select currval('piwigo_user_id_seq');
170}
171
172/**
173 *
174 * complex functions
175 *
176 */
177
178/**
179 * creates an array based on a query, this function is a very common pattern
180 * used here
181 *
182 * @param string $query
183 * @param string $fieldname
184 * @return array
185 */
186function array_from_query($query, $fieldname)
187{
188  $array = array();
189
190  $result = pwg_query($query);
191  while ($row = pg_fetch_assoc($result))
192  {
193    array_push($array, $row[$fieldname]);
194  }
195
196  return $array;
197}
198
199define('MASS_UPDATES_SKIP_EMPTY', 1);
200/**
201 * updates multiple lines in a table
202 *
203 * @param string table_name
204 * @param array dbfields
205 * @param array datas
206 * @param int flags - if MASS_UPDATES_SKIP_EMPTY - empty values do not overwrite existing ones
207 * @return void
208 */
209function mass_updates($tablename, $dbfields, $datas, $flags=0)
210{
211  if (count($datas) == 0)
212    return;
213
214  if (count($datas) < 10)
215  {
216    foreach ($datas as $data)
217    {
218      $query = '
219UPDATE '.$tablename.'
220  SET ';
221      $is_first = true;
222      foreach ($dbfields['update'] as $key)
223      {
224        $separator = $is_first ? '' : ",\n    ";
225
226        if (isset($data[$key]) and $data[$key] != '')
227        {
228          $query.= $separator.$key.' = \''.$data[$key].'\'';
229        }
230        else
231        {
232          if ($flags & MASS_UPDATES_SKIP_EMPTY )
233            continue; // next field
234          $query.= "$separator$key = NULL";
235        }
236        $is_first = false;
237      }
238      if (!$is_first)
239      {// only if one field at least updated
240        $query.= '
241  WHERE ';
242        $is_first = true;
243        foreach ($dbfields['primary'] as $key)
244        {
245          if (!$is_first)
246          {
247            $query.= ' AND ';
248          }
249          if ( isset($data[$key]) )
250          {
251            $query.= $key.' = \''.$data[$key].'\'';
252          }
253          else
254          {
255            $query.= $key.' IS NULL';
256          }
257          $is_first = false;
258        }
259        pwg_query($query);
260      }
261    } // foreach update
262  } // if mysql_ver or count<X
263  else
264  {
265    $all_fields = array_merge($dbfields['primary'], $dbfields['update']);
266    $temporary_tablename = $tablename.'_'.micro_seconds();
267    $query = '
268CREATE TABLE '.$temporary_tablename.'
269  AS SELECT * FROM '.$tablename.' WHERE 1=2';
270
271    pwg_query($query);
272    mass_inserts($temporary_tablename, $all_fields, $datas);
273    if ( $flags & MASS_UPDATES_SKIP_EMPTY )
274      $func_set = create_function('$s, $t', 'return "$s = IFNULL(t2.$s, '.$tablename.'.$s)";');
275    else
276      $func_set = create_function('$s', 'return "$s = t2.$s";');
277
278    // update of images table by joining with temporary table
279    $query = '
280UPDATE '.$tablename.'
281  SET '.
282      implode(
283        "\n    , ",
284        array_map($func_set, $dbfields['update'])
285        ).'
286FROM '.$temporary_tablename.' AS t2
287  WHERE '.
288      implode(
289        "\n    AND ",
290        array_map(
291          create_function('$s, $t', 'return "'.$tablename.'.$s = t2.$s";'),
292          $dbfields['primary']
293          )
294        );
295    pwg_query($query);
296    $query = '
297DROP TABLE '.$temporary_tablename;
298    pwg_query($query);
299  }
300}
301
302
303/**
304 * inserts multiple lines in a table
305 *
306 * @param string table_name
307 * @param array dbfields
308 * @param array inserts
309 * @return void
310 */
311
312function mass_inserts($table_name, $dbfields, $datas)
313{
314  if (count($datas) != 0)
315  {
316    $first = true;
317
318    $packet_size = 16777216;
319    $packet_size = $packet_size - 2000; // The last list of values MUST not exceed 2000 character*/
320    $query = '';
321
322    foreach ($datas as $insert)
323    {
324      if (strlen($query) >= $packet_size)
325      {
326        pwg_query($query);
327        $first = true;
328      }
329
330      if ($first)
331      {
332        $query = '
333INSERT INTO '.$table_name.'
334  ('.implode(',', $dbfields).')
335  VALUES';
336        $first = false;
337      }
338      else
339      {
340        $query .= '
341  , ';
342      }
343
344      $query .= '(';
345      foreach ($dbfields as $field_id => $dbfield)
346      {
347        if ($field_id > 0)
348        {
349          $query .= ',';
350        }
351
352        if (!isset($insert[$dbfield]) or $insert[$dbfield] === '')
353        {
354          $query .= 'NULL';
355        }
356        else
357        {
358          $query .= "'".$insert[$dbfield]."'";
359        }
360      }
361      $query .= ')';
362    }
363    pwg_query($query);
364  }
365}
366
367/**
368 * Do maintenance on all PWG tables
369 *
370 * @return none
371 */
372function do_maintenance_all_tables()
373{
374  global $prefixeTable, $page;
375
376  $all_tables = array();
377
378  // List all tables
379  $query = 'SELECT tablename FROM pg_tables
380WHERE tablename like \''.$prefixeTable.'%\'';
381
382  $all_tables = array_from_query($query, 'tablename');
383
384  // Optimize all tables
385  foreach ($all_tables as $table)
386  {
387    $query = 'VACUUM FULL '.$table;
388    pwg_query($query);
389  }
390  array_push($page['infos'],
391             l10n('Optimizations completed')
392             );
393}
394
395function pwg_db_concat_ws($array, $separator)
396{
397  $string = implode($array, ',');
398  return 'ARRAY_TO_STRING(ARRAY['.$string.'],\''.$separator.'\')';
399}
400
401function pwg_db_cast_to_text($string)
402{
403  return 'CAST('.$string.' AS TEXT)';
404}
405
406/**
407 * returns an array containing the possible values of an enum field
408 *
409 * @param string tablename
410 * @param string fieldname
411 */
412function get_enums($table, $field)
413{
414  $typname = preg_replace('/'.$GLOBALS['prefixeTable'].'/', '', $table); 
415  $typname .= '_' . $field;
416
417  $query = 'SELECT
418enumlabel FROM pg_enum JOIN pg_type
419  ON pg_enum.enumtypid=pg_type.oid
420  WHERE typname=\''.$typname.'\'
421';
422  $result = pwg_query($query);
423  while ($row = pwg_db_fetch_assoc($result))
424  {
425    $options[] = $row['enumlabel'];
426  }
427
428  return $options;
429}
430
431// get_boolean transforms a string to a boolean value. If the string is
432// "false" (case insensitive), then the boolean value false is returned. In
433// any other case, true is returned.
434function get_boolean( $string )
435{
436  $boolean = true;
437  if ('f' == $string || 'false' == $string)
438  {
439    $boolean = false;
440  }
441  return $boolean;
442}
443
444/**
445 * returns boolean string 'true' or 'false' if the given var is boolean
446 *
447 * @param mixed $var
448 * @return mixed
449 */
450function boolean_to_string($var)
451{
452  if (!empty($var) && ($var == 't'))
453  {
454    return 'true';
455  }
456  else
457  {
458    return 'false';
459  }
460}
461
462/**
463 *
464 * interval and date functions
465 *
466 */
467
468function pwg_db_get_recent_period_expression($period, $date='CURRENT_DATE')
469{
470  if ($date!='CURRENT_DATE')
471  {
472    $date = '\''.$date.'\'::date';
473  }
474
475  return '('.$date.' - \''.$period.' DAY\'::interval)::date';
476}
477
478function pwg_db_get_recent_period($period, $date='CURRENT_DATE')
479{
480  $query = 'select '.pwg_db_get_recent_period_expression($period, $date);
481  list($d) = pwg_db_fetch_row(pwg_query($query));
482
483  return $d;
484}
485
486function pwg_db_get_date_YYYYMM($date)
487{
488  return 'TO_CHAR('.$date.', \'YYYYMM\')';
489}
490
491function pwg_db_get_date_MMDD($date)
492{
493  return 'TO_CHAR('.$date.', \'MMDD\')';
494}
495
496function pwg_db_get_year($date)
497{
498  return 'EXTRACT(YEAR FROM '.$date.')';
499}
500
501function pwg_db_get_month($date)
502{
503  return 'EXTRACT(MONTH FROM '.$date.')';
504}
505
506function pwg_db_get_week($date, $mode=null)
507{
508  return 'EXTRACT(WEEK FROM '.$date.')';
509}
510
511function pwg_db_get_dayofmonth($date)
512{
513  return 'EXTRACT(DAY FROM '.$date.')';
514}
515
516function pwg_db_get_dayofweek($date)
517{
518  return 'EXTRACT(DOW FROM '.$date.')::INTEGER - 1';
519}
520
521function pwg_db_get_weekday($date)
522{
523  return 'EXTRACT(ISODOW FROM '.$date.')::INTEGER - 1';
524}
525
526// my_error returns (or send to standard output) the message concerning the
527// error occured for the last mysql query.
528function my_error($header, $die)
529{
530  $error = '[pgsql error]'.pg_last_error()."\n";
531  $error .= $header;
532
533  if ($die)
534  {
535    fatal_error($error);
536  }
537  echo("<pre>");
538  trigger_error($error, E_USER_WARNING);
539  echo("</pre>");
540}
541
542
543?>
Note: See TracBrowser for help on using the repository browser.