dolibarr  13.0.2
pgsql.class.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2001 Fabien Seisen <seisen@linuxfr.org>
3  * Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
4  * Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net>
5  * Copyright (C) 2004 Sebastien Di Cintio <sdicintio@ressource-toi.org>
6  * Copyright (C) 2004 Benoit Mortier <benoit.mortier@opensides.be>
7  * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
8  * Copyright (C) 2012 Yann Droneaud <yann@droneaud.fr>
9  * Copyright (C) 2012 Florian Henry <florian.henry@open-concept.pro>
10  * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
11  *
12  * This program is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <https://www.gnu.org/licenses/>.
24  */
25 
31 require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
32 
36 class DoliDBPgsql extends DoliDB
37 {
39  public $type = 'pgsql'; // Name of manager
41  const LABEL = 'PostgreSQL'; // Label of manager
43  public $forcecharset = 'UTF8'; // Can't be static as it may be forced with a dynamic value
45  public $forcecollate = ''; // Can't be static as it may be forced with a dynamic value
47  const VERSIONMIN = '9.0.0'; // Version min database
49  private $_results;
50 
51  public $unescapeslashquot;
52  public $standard_conforming_strings;
53 
65  public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
66  {
67  global $conf, $langs;
68 
69  // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
70  if (!empty($conf->db->character_set)) $this->forcecharset = $conf->db->character_set;
71  if (!empty($conf->db->dolibarr_main_db_collation)) $this->forcecollate = $conf->db->dolibarr_main_db_collation;
72 
73  $this->database_user = $user;
74  $this->database_host = $host;
75  $this->database_port = $port;
76 
77  $this->transaction_opened = 0;
78 
79  //print "Name DB: $host,$user,$pass,$name<br>";
80 
81  if (!function_exists("pg_connect"))
82  {
83  $this->connected = false;
84  $this->ok = false;
85  $this->error = "Pgsql PHP functions are not available in this version of PHP";
86  dol_syslog(get_class($this)."::DoliDBPgsql : Pgsql PHP functions are not available in this version of PHP", LOG_ERR);
87  return $this->ok;
88  }
89 
90  if (!$host)
91  {
92  $this->connected = false;
93  $this->ok = false;
94  $this->error = $langs->trans("ErrorWrongHostParameter");
95  dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect, wrong host parameters", LOG_ERR);
96  return $this->ok;
97  }
98 
99  // Essai connexion serveur
100  //print "$host, $user, $pass, $name, $port";
101  $this->db = $this->connect($host, $user, $pass, $name, $port);
102 
103  if ($this->db)
104  {
105  $this->connected = true;
106  $this->ok = true;
107  } else {
108  // host, login ou password incorrect
109  $this->connected = false;
110  $this->ok = false;
111  $this->error = 'Host, login or password incorrect';
112  dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect ".$this->error, LOG_ERR);
113  }
114 
115  // Si connexion serveur ok et si connexion base demandee, on essaie connexion base
116  if ($this->connected && $name)
117  {
118  if ($this->select_db($name))
119  {
120  $this->database_selected = true;
121  $this->database_name = $name;
122  $this->ok = true;
123  } else {
124  $this->database_selected = false;
125  $this->database_name = '';
126  $this->ok = false;
127  $this->error = $this->error();
128  dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Select_db ".$this->error, LOG_ERR);
129  }
130  } else {
131  // Pas de selection de base demandee, ok ou ko
132  $this->database_selected = false;
133  }
134 
135  return $this->ok;
136  }
137 
138 
147  public static function convertSQLFromMysql($line, $type = 'auto', $unescapeslashquot = false)
148  {
149  global $conf;
150 
151  // Removed empty line if this is a comment line for SVN tagging
152  if (preg_match('/^--\s\$Id/i', $line)) {
153  return '';
154  }
155  // Return line if this is a comment
156  if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line))
157  {
158  return $line;
159  }
160  if ($line != "")
161  {
162  // group_concat support (PgSQL >= 9.0)
163  // Replace group_concat(x) or group_concat(x SEPARATOR ',') with string_agg(x, ',')
164  $line = preg_replace('/GROUP_CONCAT/i', 'STRING_AGG', $line);
165  $line = preg_replace('/ SEPARATOR/i', ',', $line);
166  $line = preg_replace('/STRING_AGG\(([^,\)]+)\)/i', 'STRING_AGG(\\1, \',\')', $line);
167  //print $line."\n";
168 
169  if ($type == 'auto')
170  {
171  if (preg_match('/ALTER TABLE/i', $line)) $type = 'dml';
172  elseif (preg_match('/CREATE TABLE/i', $line)) $type = 'dml';
173  elseif (preg_match('/DROP TABLE/i', $line)) $type = 'dml';
174  }
175 
176  $line = preg_replace('/ as signed\)/i', ' as integer)', $line);
177 
178  if ($type == 'dml')
179  {
180  $reg = array();
181 
182  $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
183 
184  // we are inside create table statement so lets process datatypes
185  if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
186  $line = preg_replace('/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i', ');', $line);
187  $line = preg_replace('/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i', ');', $line);
188  $line = preg_replace('/,$/', '', $line);
189  }
190 
191  // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
192  if (preg_match('/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
193  $newline = preg_replace('/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 SERIAL PRIMARY KEY', $line);
194  //$line = "-- ".$line." replaced by --\n".$newline;
195  $line = $newline;
196  }
197 
198  if (preg_match('/[\s\t\(]*(\w*)[\s\t]+bigint.*auto_increment/i', $line, $reg)) {
199  $newline = preg_replace('/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+bigint.*auto_increment[^,]*/i', '\\1 \\2 BIGSERIAL PRIMARY KEY', $line);
200  //$line = "-- ".$line." replaced by --\n".$newline;
201  $line = $newline;
202  }
203 
204  // tinyint type conversion
205  $line = preg_replace('/tinyint\(?[0-9]*\)?/', 'smallint', $line);
206  $line = preg_replace('/tinyint/i', 'smallint', $line);
207 
208  // nuke unsigned
209  $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
210 
211  // blob -> text
212  $line = preg_replace('/\w*blob/i', 'text', $line);
213 
214  // tinytext/mediumtext -> text
215  $line = preg_replace('/tinytext/i', 'text', $line);
216  $line = preg_replace('/mediumtext/i', 'text', $line);
217  $line = preg_replace('/longtext/i', 'text', $line);
218 
219  $line = preg_replace('/text\([0-9]+\)/i', 'text', $line);
220 
221  // change not null datetime field to null valid ones
222  // (to support remapping of "zero time" to null
223  $line = preg_replace('/datetime not null/i', 'datetime', $line);
224  $line = preg_replace('/datetime/i', 'timestamp', $line);
225 
226  // double -> numeric
227  $line = preg_replace('/^double/i', 'numeric', $line);
228  $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
229  // float -> numeric
230  $line = preg_replace('/^float/i', 'numeric', $line);
231  $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
232 
233  //Check tms timestamp field case (in Mysql this field is defautled to now and
234  // on update defaulted by now
235  $line = preg_replace('/(\s*)tms(\s*)timestamp/i', '\\1tms timestamp without time zone DEFAULT now() NOT NULL', $line);
236 
237  // nuke DEFAULT CURRENT_TIMESTAMP
238  $line = preg_replace('/(\s*)DEFAULT(\s*)CURRENT_TIMESTAMP/i', '\\1', $line);
239 
240  // nuke ON UPDATE CURRENT_TIMESTAMP
241  $line = preg_replace('/(\s*)ON(\s*)UPDATE(\s*)CURRENT_TIMESTAMP/i', '\\1', $line);
242 
243  // unique index(field1,field2)
244  if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i', $line))
245  {
246  $line = preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i', 'UNIQUE\(\\1\)', $line);
247  }
248 
249  // We remove end of requests "AFTER fieldxxx"
250  $line = preg_replace('/\sAFTER [a-z0-9_]+/i', '', $line);
251 
252  // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
253  $line = preg_replace('/ALTER TABLE [a-z0-9_]+\s+DROP INDEX/i', 'DROP INDEX', $line);
254 
255  // Translate order to rename fields
256  if (preg_match('/ALTER TABLE ([a-z0-9_]+)\s+CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg))
257  {
258  $line = "-- ".$line." replaced by --\n";
259  $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
260  }
261 
262  // Translate order to modify field format
263  if (preg_match('/ALTER TABLE ([a-z0-9_]+)\s+MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg))
264  {
265  $line = "-- ".$line." replaced by --\n";
266  $newreg3 = $reg[3];
267  $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
268  $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
269  $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
270  $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
271  $newreg3 = preg_replace('/ DEFAULT \'?[0-9a-zA-Z_@]*\'?/i', '', $newreg3);
272  $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
273  // TODO Add alter to set default value or null/not null if there is this in $reg[3]
274  }
275 
276  // alter table add primary key (field1, field2 ...) -> We remove the primary key name not accepted by PostGreSQL
277  // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity)
278  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i', $line, $reg))
279  {
280  $line = "-- ".$line." replaced by --\n";
281  $line .= "ALTER TABLE ".$reg[1]." ADD PRIMARY KEY (".$reg[3];
282  }
283 
284  // Translate order to drop primary keys
285  // ALTER TABLE llx_dolibarr_modules DROP PRIMARY KEY pk_xxx
286  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+PRIMARY\s+KEY\s*([^;]+)$/i', $line, $reg))
287  {
288  $line = "-- ".$line." replaced by --\n";
289  $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
290  }
291 
292  // Translate order to drop foreign keys
293  // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx
294  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg))
295  {
296  $line = "-- ".$line." replaced by --\n";
297  $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
298  }
299 
300  // Translate order to add foreign keys
301  // ALTER TABLE llx_tablechild ADD CONSTRAINT fk_tablechild_fk_fieldparent FOREIGN KEY (fk_fieldparent) REFERENCES llx_tableparent (rowid)
302  if (preg_match('/ALTER\s+TABLE\s+(.*)\s*ADD CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*(.*)$/i', $line, $reg))
303  {
304  $line = preg_replace('/;$/', '', $line);
305  $line .= " DEFERRABLE INITIALLY IMMEDIATE;";
306  }
307 
308  // alter table add [unique] [index] (field1, field2 ...)
309  // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
310  if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i', $line, $reg))
311  {
312  $fieldlist = $reg[4];
313  $idxname = $reg[3];
314  $tablename = $reg[1];
315  $line = "-- ".$line." replaced by --\n";
316  $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
317  }
318  }
319 
320  // To have postgresql case sensitive
321  $count_like = 0;
322  $line = str_replace(' LIKE \'', ' ILIKE \'', $line, $count_like);
323  if (!empty($conf->global->PSQL_USE_UNACCENT) && $count_like > 0)
324  {
325  // @see https://docs.postgresql.fr/11/unaccent.html : 'unaccent()' function must be installed before
326  $line = preg_replace('/\s+(\(+\s*)([a-zA-Z0-9\-\_\.]+) ILIKE /', ' \1unaccent(\2) ILIKE ', $line);
327  }
328 
329  $line = str_replace(' LIKE BINARY \'', ' LIKE \'', $line);
330 
331  // Replace INSERT IGNORE into INSERT
332  $line = preg_replace('/^INSERT IGNORE/', 'INSERT', $line);
333 
334  // Delete using criteria on other table must not declare twice the deleted table
335  // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
336  if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg))
337  {
338  if ($reg[1] == $reg[2]) // If same table, we remove second one
339  {
340  $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
341  }
342  }
343 
344  // Remove () in the tables in FROM if 1 table
345  $line = preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i', 'FROM \\1', $line);
346  //print $line."\n";
347 
348  // Remove () in the tables in FROM if 2 table
349  $line = preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i', 'FROM \\1, \\2', $line);
350  //print $line."\n";
351 
352  // Remove () in the tables in FROM if 3 table
353  $line = preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i', 'FROM \\1, \\2, \\3', $line);
354  //print $line."\n";
355 
356  // Remove () in the tables in FROM if 4 table
357  $line = preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i', 'FROM \\1, \\2, \\3, \\4', $line);
358  //print $line."\n";
359 
360  // Remove () in the tables in FROM if 5 table
361  $line = preg_replace('/FROM\s*\(([a-z_]+\s+as\s+[a-z_]+)\s*,\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*),\s*([a-z_]+\s+as\s+[a-z_]+\s*)\)/i', 'FROM \\1, \\2, \\3, \\4, \\5', $line);
362  //print $line."\n";
363 
364  // Replace espacing \' by ''.
365  // By default we do not (should be already done by db->escape function if required
366  // except for sql insert in data file that are mysql escaped so we removed them to
367  // be compatible with standard_conforming_strings=on that considers \ as ordinary character).
368  if ($unescapeslashquot) $line = preg_replace("/\\\'/", "''", $line);
369 
370  //print "type=".$type." newline=".$line."<br>\n";
371  }
372 
373  return $line;
374  }
375 
376  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
385  public function select_db($database)
386  {
387  // phpcs:enable
388  if ($database == $this->database_name) {
389  return true;
390  } else {
391  return false;
392  }
393  }
394 
406  public function connect($host, $login, $passwd, $name, $port = 0)
407  {
408  // use pg_pconnect() instead of pg_connect() if you want to use persistent connection costing 1ms, instead of 30ms for non persistent
409 
410  $this->db = false;
411 
412  // connections parameters must be protected (only \ and ' according to pg_connect() manual)
413  $host = str_replace(array("\\", "'"), array("\\\\", "\\'"), $host);
414  $login = str_replace(array("\\", "'"), array("\\\\", "\\'"), $login);
415  $passwd = str_replace(array("\\", "'"), array("\\\\", "\\'"), $passwd);
416  $name = str_replace(array("\\", "'"), array("\\\\", "\\'"), $name);
417  $port = str_replace(array("\\", "'"), array("\\\\", "\\'"), $port);
418 
419  if (!$name) $name = "postgres"; // When try to connect using admin user
420 
421  // try first Unix domain socket (local)
422  if ((!empty($host) && $host == "socket") && !defined('NOLOCALSOCKETPGCONNECT'))
423  {
424  $con_string = "dbname='".$name."' user='".$login."' password='".$passwd."'"; // $name may be empty
425  $this->db = @pg_connect($con_string);
426  }
427 
428  // if local connection failed or not requested, use TCP/IP
429  if (!$this->db)
430  {
431  if (!$host) $host = "localhost";
432  if (!$port) $port = 5432;
433 
434  $con_string = "host='".$host."' port='".$port."' dbname='".$name."' user='".$login."' password='".$passwd."'";
435  $this->db = @pg_connect($con_string);
436  }
437 
438  // now we test if at least one connect method was a success
439  if ($this->db)
440  {
441  $this->database_name = $name;
442  pg_set_error_verbosity($this->db, PGSQL_ERRORS_VERBOSE); // Set verbosity to max
443  pg_query($this->db, "set datestyle = 'ISO, YMD';");
444  }
445 
446  return $this->db;
447  }
448 
454  public function getVersion()
455  {
456  $resql = $this->query('SHOW server_version');
457  if ($resql)
458  {
459  $liste = $this->fetch_array($resql);
460  return $liste['server_version'];
461  }
462  return '';
463  }
464 
470  public function getDriverInfo()
471  {
472  return 'pgsql php driver';
473  }
474 
481  public function close()
482  {
483  if ($this->db)
484  {
485  if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
486  $this->connected = false;
487  return pg_close($this->db);
488  }
489  return false;
490  }
491 
500  public function query($query, $usesavepoint = 0, $type = 'auto')
501  {
502  global $conf;
503 
504  $query = trim($query);
505 
506  // Convert MySQL syntax to PostgresSQL syntax
507  $query = $this->convertSQLFromMysql($query, $type, ($this->unescapeslashquot && $this->standard_conforming_strings));
508  //print "After convertSQLFromMysql:\n".$query."<br>\n";
509 
510  if (!empty($conf->global->MAIN_DB_AUTOFIX_BAD_SQL_REQUEST))
511  {
512  // Fix bad formed requests. If request contains a date without quotes, we fix this but this should not occurs.
513  $loop = true;
514  while ($loop)
515  {
516  if (preg_match('/([^\'])([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])/', $query))
517  {
518  $query = preg_replace('/([^\'])([0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9])/', '\\1\'\\2\'', $query);
519  dol_syslog("Warning: Bad formed request converted into ".$query, LOG_WARNING);
520  } else $loop = false;
521  }
522  }
523 
524  if ($usesavepoint && $this->transaction_opened)
525  {
526  @pg_query($this->db, 'SAVEPOINT mysavepoint');
527  }
528 
529  if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK')))
530  {
531  $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
532  dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
533  }
534 
535  $ret = @pg_query($this->db, $query);
536 
537  //print $query;
538  if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) // Si requete utilisateur, on la sauvegarde ainsi que son resultset
539  {
540  if (!$ret)
541  {
542  if ($this->errno() != 'DB_ERROR_25P02') // Do not overwrite errors if this is a consecutive error
543  {
544  $this->lastqueryerror = $query;
545  $this->lasterror = $this->error();
546  $this->lasterrno = $this->errno();
547 
548  if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
549  dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterror." (".$this->lasterrno.")", LOG_ERR);
550  dol_syslog(get_class($this)."::query SQL Error usesavepoint = ".$usesavepoint, LOG_ERR);
551  }
552 
553  if ($usesavepoint && $this->transaction_opened) // Warning, after that errno will be erased
554  {
555  @pg_query($this->db, 'ROLLBACK TO SAVEPOINT mysavepoint');
556  }
557  }
558  $this->lastquery = $query;
559  $this->_results = $ret;
560  }
561 
562  return $ret;
563  }
564 
565  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
572  public function fetch_object($resultset)
573  {
574  // phpcs:enable
575  // If resultset not provided, we take the last used by connexion
576  if (!is_resource($resultset)) { $resultset = $this->_results; }
577  return pg_fetch_object($resultset);
578  }
579 
580  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
587  public function fetch_array($resultset)
588  {
589  // phpcs:enable
590  // If resultset not provided, we take the last used by connexion
591  if (!is_resource($resultset)) { $resultset = $this->_results; }
592  return pg_fetch_array($resultset);
593  }
594 
595  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
602  public function fetch_row($resultset)
603  {
604  // phpcs:enable
605  // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
606  if (!is_resource($resultset)) { $resultset = $this->_results; }
607  return pg_fetch_row($resultset);
608  }
609 
610  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
618  public function num_rows($resultset)
619  {
620  // phpcs:enable
621  // If resultset not provided, we take the last used by connexion
622  if (!is_resource($resultset)) { $resultset = $this->_results; }
623  return pg_num_rows($resultset);
624  }
625 
626  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
634  public function affected_rows($resultset)
635  {
636  // phpcs:enable
637  // If resultset not provided, we take the last used by connexion
638  if (!is_resource($resultset)) { $resultset = $this->_results; }
639  // pgsql necessite un resultset pour cette fonction contrairement
640  // a mysql qui prend un link de base
641  return pg_affected_rows($resultset);
642  }
643 
644 
651  public function free($resultset = null)
652  {
653  // If resultset not provided, we take the last used by connexion
654  if (!is_resource($resultset)) { $resultset = $this->_results; }
655  // Si resultset en est un, on libere la memoire
656  if (is_resource($resultset)) pg_free_result($resultset);
657  }
658 
659 
667  public function plimit($limit = 0, $offset = 0)
668  {
669  global $conf;
670  if (empty($limit)) return "";
671  if ($limit < 0) $limit = $conf->liste_limit;
672  if ($offset > 0) return " LIMIT ".$limit." OFFSET ".$offset." ";
673  else return " LIMIT $limit ";
674  }
675 
676 
683  public function escape($stringtoencode)
684  {
685  return pg_escape_string($stringtoencode);
686  }
687 
696  public function ifsql($test, $resok, $resko)
697  {
698  return '(CASE WHEN '.$test.' THEN '.$resok.' ELSE '.$resko.' END)';
699  }
700 
706  public function errno()
707  {
708  if (!$this->connected) {
709  // Si il y a eu echec de connexion, $this->db n'est pas valide.
710  return 'DB_ERROR_FAILED_TO_CONNECT';
711  } else {
712  // Constants to convert error code to a generic Dolibarr error code
713  $errorcode_map = array(
714  1004 => 'DB_ERROR_CANNOT_CREATE',
715  1005 => 'DB_ERROR_CANNOT_CREATE',
716  1006 => 'DB_ERROR_CANNOT_CREATE',
717  1007 => 'DB_ERROR_ALREADY_EXISTS',
718  1008 => 'DB_ERROR_CANNOT_DROP',
719  1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
720  1044 => 'DB_ERROR_ACCESSDENIED',
721  1046 => 'DB_ERROR_NODBSELECTED',
722  1048 => 'DB_ERROR_CONSTRAINT',
723  '42P07' => 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS',
724  '42703' => 'DB_ERROR_NOSUCHFIELD',
725  1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
726  42701=> 'DB_ERROR_COLUMN_ALREADY_EXISTS',
727  '42710' => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
728  '23505' => 'DB_ERROR_RECORD_ALREADY_EXISTS',
729  '42704' => 'DB_ERROR_NO_INDEX_TO_DROP', // May also be Type xxx does not exists
730  '42601' => 'DB_ERROR_SYNTAX',
731  '42P16' => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
732  1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
733  1091 => 'DB_ERROR_NOSUCHFIELD',
734  1100 => 'DB_ERROR_NOT_LOCKED',
735  1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
736  '42P01' => 'DB_ERROR_NOSUCHTABLE',
737  '23503' => 'DB_ERROR_NO_PARENT',
738  1217 => 'DB_ERROR_CHILD_EXISTS',
739  1451 => 'DB_ERROR_CHILD_EXISTS',
740  '42P04' => 'DB_DATABASE_ALREADY_EXISTS'
741  );
742 
743  $errorlabel = pg_last_error($this->db);
744  $errorcode = '';
745  if (preg_match('/: *([0-9P]+):/', $errorlabel, $reg))
746  {
747  $errorcode = $reg[1];
748  if (isset($errorcode_map[$errorcode]))
749  {
750  return $errorcode_map[$errorcode];
751  }
752  }
753  $errno = $errorcode ? $errorcode : $errorlabel;
754  return ($errno ? 'DB_ERROR_'.$errno : '0');
755  }
756  // '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => 'DB_ERROR_NOSUCHTABLE',
757  // '/table [\"\'].*[\"\'] does not exist/' => 'DB_ERROR_NOSUCHTABLE',
758  // '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => 'DB_ERROR_RECORD_ALREADY_EXISTS',
759  // '/divide by zero$/' => 'DB_ERROR_DIVZERO',
760  // '/pg_atoi: error in .*: can\'t parse /' => 'DB_ERROR_INVALID_NUMBER',
761  // '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => 'DB_ERROR_NOSUCHFIELD',
762  // '/parser: parse error at or near \"/' => 'DB_ERROR_SYNTAX',
763  // '/referential integrity violation/' => 'DB_ERROR_CONSTRAINT'
764  }
765 
771  public function error()
772  {
773  return pg_last_error($this->db);
774  }
775 
776  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
784  public function last_insert_id($tab, $fieldid = 'rowid')
785  {
786  // phpcs:enable
787  //$result = pg_query($this->db,"SELECT MAX(".$fieldid.") FROM ".$tab);
788  $result = pg_query($this->db, "SELECT currval('".$tab."_".$fieldid."_seq')");
789  if (!$result)
790  {
791  print pg_last_error($this->db);
792  exit;
793  }
794  //$nbre = pg_num_rows($result);
795  $row = pg_fetch_result($result, 0, 0);
796  return $row;
797  }
798 
807  public function encrypt($fieldorvalue, $withQuotes = 0)
808  {
809  global $conf;
810 
811  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
812  $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
813 
814  //Encryption key
815  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
816 
817  $return = $fieldorvalue;
818  return ($withQuotes ? "'" : "").$this->escape($return).($withQuotes ? "'" : "");
819  }
820 
821 
828  public function decrypt($value)
829  {
830  global $conf;
831 
832  // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
833  $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
834 
835  //Encryption key
836  $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
837 
838  $return = $value;
839  return $return;
840  }
841 
842 
843  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
849  public function DDLGetConnectId()
850  {
851  // phpcs:enable
852  return '?';
853  }
854 
855 
856 
857  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
869  public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
870  {
871  // phpcs:enable
872  if (empty($charset)) $charset = $this->forcecharset;
873  if (empty($collation)) $collation = $this->forcecollate;
874 
875  // Test charset match LC_TYPE (pgsql error otherwise)
876  //print $charset.' '.setlocale(LC_CTYPE,'0'); exit;
877 
878  $sql = 'CREATE DATABASE "'.$database.'" OWNER "'.$owner.'" ENCODING \''.$charset.'\'';
879  dol_syslog($sql, LOG_DEBUG);
880  $ret = $this->query($sql);
881  return $ret;
882  }
883 
884  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
892  public function DDLListTables($database, $table = '')
893  {
894  // phpcs:enable
895  $listtables = array();
896 
897  $like = '';
898  if ($table) $like = " AND table_name LIKE '".$this->escape($table)."'";
899  $result = pg_query($this->db, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'".$like." ORDER BY table_name");
900  if ($result)
901  {
902  while ($row = $this->fetch_row($result))
903  {
904  $listtables[] = $row[0];
905  }
906  }
907  return $listtables;
908  }
909 
910  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
918  public function DDLInfoTable($table)
919  {
920  // phpcs:enable
921  $infotables = array();
922 
923  $sql = "SELECT ";
924  $sql .= " infcol.column_name as \"Column\",";
925  $sql .= " CASE WHEN infcol.character_maximum_length IS NOT NULL THEN infcol.udt_name || '('||infcol.character_maximum_length||')'";
926  $sql .= " ELSE infcol.udt_name";
927  $sql .= " END as \"Type\",";
928  $sql .= " infcol.collation_name as \"Collation\",";
929  $sql .= " infcol.is_nullable as \"Null\",";
930  $sql .= " '' as \"Key\",";
931  $sql .= " infcol.column_default as \"Default\",";
932  $sql .= " '' as \"Extra\",";
933  $sql .= " '' as \"Privileges\"";
934  $sql .= " FROM information_schema.columns infcol";
935  $sql .= " WHERE table_schema='public' ";
936  $sql .= " AND table_name='".$this->escape($table)."'";
937  $sql .= " ORDER BY ordinal_position;";
938 
939  dol_syslog($sql, LOG_DEBUG);
940  $result = $this->query($sql);
941  if ($result)
942  {
943  while ($row = $this->fetch_row($result))
944  {
945  $infotables[] = $row;
946  }
947  }
948  return $infotables;
949  }
950 
951 
952  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
965  public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
966  {
967  // phpcs:enable
968  // FIXME: $fulltext_keys parameter is unused
969 
970  // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
971  // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
972  $sql = "create table ".$table."(";
973  $i = 0;
974  foreach ($fields as $field_name => $field_desc)
975  {
976  $sqlfields[$i] = $field_name." ";
977  $sqlfields[$i] .= $field_desc['type'];
978  if (preg_match("/^[^\s]/i", $field_desc['value']))
979  $sqlfields[$i] .= "(".$field_desc['value'].")";
980  elseif (preg_match("/^[^\s]/i", $field_desc['attribute']))
981  $sqlfields[$i] .= " ".$field_desc['attribute'];
982  elseif (preg_match("/^[^\s]/i", $field_desc['default']))
983  {
984  if (preg_match("/null/i", $field_desc['default']))
985  $sqlfields[$i] .= " default ".$field_desc['default'];
986  else $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
987  } elseif (preg_match("/^[^\s]/i", $field_desc['null']))
988  $sqlfields[$i] .= " ".$field_desc['null'];
989 
990  elseif (preg_match("/^[^\s]/i", $field_desc['extra']))
991  $sqlfields[$i] .= " ".$field_desc['extra'];
992  $i++;
993  }
994  if ($primary_key != "")
995  $pk = "primary key(".$primary_key.")";
996 
997  if (is_array($unique_keys))
998  {
999  $i = 0;
1000  foreach ($unique_keys as $key => $value)
1001  {
1002  $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
1003  $i++;
1004  }
1005  }
1006  if (is_array($keys))
1007  {
1008  $i = 0;
1009  foreach ($keys as $key => $value)
1010  {
1011  $sqlk[$i] = "KEY ".$key." (".$value.")";
1012  $i++;
1013  }
1014  }
1015  $sql .= implode(',', $sqlfields);
1016  if ($primary_key != "")
1017  $sql .= ",".$pk;
1018  if (is_array($unique_keys))
1019  $sql .= ",".implode(',', $sqluq);
1020  if (is_array($keys))
1021  $sql .= ",".implode(',', $sqlk);
1022  $sql .= ") type=".$type;
1023 
1024  dol_syslog($sql, LOG_DEBUG);
1025  if (!$this->query($sql))
1026  return -1;
1027  else return 1;
1028  }
1029 
1030  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1037  public function DDLDropTable($table)
1038  {
1039  // phpcs:enable
1040  $sql = "DROP TABLE ".$table;
1041 
1042  if (!$this->query($sql))
1043  return -1;
1044  else return 1;
1045  }
1046 
1047  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1057  public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1058  {
1059  // phpcs:enable
1060  // Note: using ' on user does not works with pgsql
1061  $sql = "CREATE USER ".$this->escape($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'";
1062 
1063  dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1064  $resql = $this->query($sql);
1065  if (!$resql)
1066  {
1067  return -1;
1068  }
1069 
1070  return 1;
1071  }
1072 
1073  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1081  public function DDLDescTable($table, $field = "")
1082  {
1083  // phpcs:enable
1084  $sql = "SELECT attname FROM pg_attribute, pg_type WHERE typname = '".$this->escape($table)."' AND attrelid = typrelid";
1085  $sql .= " AND attname NOT IN ('cmin', 'cmax', 'ctid', 'oid', 'tableoid', 'xmin', 'xmax')";
1086  if ($field) $sql .= " AND attname = '".$this->escape($field)."'";
1087 
1088  dol_syslog($sql, LOG_DEBUG);
1089  $this->_results = $this->query($sql);
1090  return $this->_results;
1091  }
1092 
1093  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1103  public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1104  {
1105  // phpcs:enable
1106  // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1107  // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1108  $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1109  $sql .= $field_desc['type'];
1110  if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1111  if (!in_array($field_desc['type'], array('int', 'date', 'datetime')) && $field_desc['value'])
1112  {
1113  $sql .= "(".$field_desc['value'].")";
1114  }
1115  }
1116  if (preg_match("/^[^\s]/i", $field_desc['attribute']))
1117  $sql .= " ".$field_desc['attribute'];
1118  if (preg_match("/^[^\s]/i", $field_desc['null']))
1119  $sql .= " ".$field_desc['null'];
1120  if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1121  if (preg_match("/null/i", $field_desc['default'])) {
1122  $sql .= " default ".$field_desc['default'];
1123  } else {
1124  $sql .= " default '".$this->escape($field_desc['default'])."'";
1125  }
1126  }
1127  if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1128  $sql .= " ".$field_desc['extra'];
1129  }
1130  $sql .= " ".$field_position;
1131 
1132  dol_syslog($sql, LOG_DEBUG);
1133  if (!$this -> query($sql))
1134  return -1;
1135  return 1;
1136  }
1137 
1138  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1147  public function DDLUpdateField($table, $field_name, $field_desc)
1148  {
1149  // phpcs:enable
1150  $sql = "ALTER TABLE ".$table;
1151  $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
1152  if (in_array($field_desc['type'], array('double', 'tinyint', 'int', 'varchar')) && $field_desc['value']) {
1153  $sql .= "(".$field_desc['value'].")";
1154  }
1155 
1156  if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL')
1157  {
1158  // We will try to change format of column to NOT NULL. To be sure the ALTER works, we try to update fields that are NULL
1159  if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text')
1160  {
1161  $sqlbis = "UPDATE ".$table." SET ".$field_name." = '".$this->escape($field_desc['default'] ? $field_desc['default'] : '')."' WHERE ".$field_name." IS NULL";
1162  $this->query($sqlbis);
1163  } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int')
1164  {
1165  $sqlbis = "UPDATE ".$table." SET ".$field_name." = ".((int) $this->escape($field_desc['default'] ? $field_desc['default'] : 0))." WHERE ".$field_name." IS NULL";
1166  $this->query($sqlbis);
1167  }
1168  }
1169 
1170  if ($field_desc['default'] != '')
1171  {
1172  if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') $sql .= " DEFAULT ".$this->escape($field_desc['default']);
1173  elseif ($field_desc['type'] != 'text') $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'"; // Default not supported on text fields
1174  }
1175 
1176  dol_syslog($sql, LOG_DEBUG);
1177  if (!$this->query($sql))
1178  return -1;
1179  return 1;
1180  }
1181 
1182  // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1190  public function DDLDropField($table, $field_name)
1191  {
1192  // phpcs:enable
1193  $sql = "ALTER TABLE ".$table." DROP COLUMN ".$field_name;
1194  dol_syslog($sql, LOG_DEBUG);
1195  if (!$this->query($sql))
1196  {
1197  $this->error = $this->lasterror();
1198  return -1;
1199  }
1200  return 1;
1201  }
1202 
1209  {
1210  $resql = $this->query('SHOW SERVER_ENCODING');
1211  if ($resql)
1212  {
1213  $liste = $this->fetch_array($resql);
1214  return $liste['server_encoding'];
1215  } else return '';
1216  }
1217 
1223  public function getListOfCharacterSet()
1224  {
1225  $resql = $this->query('SHOW SERVER_ENCODING');
1226  $liste = array();
1227  if ($resql)
1228  {
1229  $i = 0;
1230  while ($obj = $this->fetch_object($resql))
1231  {
1232  $liste[$i]['charset'] = $obj->server_encoding;
1233  $liste[$i]['description'] = 'Default database charset';
1234  $i++;
1235  }
1236  $this->free($resql);
1237  } else {
1238  return null;
1239  }
1240  return $liste;
1241  }
1242 
1249  {
1250  $resql = $this->query('SHOW LC_COLLATE');
1251  if ($resql)
1252  {
1253  $liste = $this->fetch_array($resql);
1254  return $liste['lc_collate'];
1255  } else return '';
1256  }
1257 
1263  public function getListOfCollation()
1264  {
1265  $resql = $this->query('SHOW LC_COLLATE');
1266  $liste = array();
1267  if ($resql)
1268  {
1269  $i = 0;
1270  while ($obj = $this->fetch_object($resql))
1271  {
1272  $liste[$i]['collation'] = $obj->lc_collate;
1273  $i++;
1274  }
1275  $this->free($resql);
1276  } else {
1277  return null;
1278  }
1279  return $liste;
1280  }
1281 
1287  public function getPathOfDump()
1288  {
1289  $fullpathofdump = '/pathtopgdump/pg_dump';
1290 
1291  if (file_exists('/usr/bin/pg_dump'))
1292  {
1293  $fullpathofdump = '/usr/bin/pg_dump';
1294  } else {
1295  // TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
1296  $resql = $this->query('SHOW data_directory');
1297  if ($resql)
1298  {
1299  $liste = $this->fetch_array($resql);
1300  $basedir = $liste['data_directory'];
1301  $fullpathofdump = preg_replace('/data$/', 'bin', $basedir).'/pg_dump';
1302  }
1303  }
1304 
1305  return $fullpathofdump;
1306  }
1307 
1313  public function getPathOfRestore()
1314  {
1315  //$tool='pg_restore';
1316  $tool = 'psql';
1317 
1318  $fullpathofdump = '/pathtopgrestore/'.$tool;
1319 
1320  if (file_exists('/usr/bin/'.$tool))
1321  {
1322  $fullpathofdump = '/usr/bin/'.$tool;
1323  } else {
1324  // TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
1325  $resql = $this->query('SHOW data_directory');
1326  if ($resql)
1327  {
1328  $liste = $this->fetch_array($resql);
1329  $basedir = $liste['data_directory'];
1330  $fullpathofdump = preg_replace('/data$/', 'bin', $basedir).'/'.$tool;
1331  }
1332  }
1333 
1334  return $fullpathofdump;
1335  }
1336 
1343  public function getServerParametersValues($filter = '')
1344  {
1345  $result = array();
1346 
1347  $resql = 'select name,setting from pg_settings';
1348  if ($filter) $resql .= " WHERE name = '".$this->escape($filter)."'";
1349  $resql = $this->query($resql);
1350  if ($resql)
1351  {
1352  while ($obj = $this->fetch_object($resql)) $result[$obj->name] = $obj->setting;
1353  }
1354 
1355  return $result;
1356  }
1357 
1364  public function getServerStatusValues($filter = '')
1365  {
1366  /* This is to return current running requests.
1367  $sql='SELECT datname,procpid,current_query FROM pg_stat_activity ORDER BY procpid';
1368  if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1369  $resql=$this->query($sql);
1370  if ($resql)
1371  {
1372  $obj=$this->fetch_object($resql);
1373  $result[$obj->Variable_name]=$obj->Value;
1374  }
1375  */
1376 
1377  return array();
1378  }
1379 }
affected_rows($resultset)
Return the number of lines in the result of a request INSERT, DELETE or UPDATE.
lastqueryerror()
Return last query in error.
DDLUpdateField($table, $field_name, $field_desc)
Update format of a field into a table.
DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys=null, $fulltext_keys=null, $keys=null)
Create a table into database.
static convertSQLFromMysql($line, $type= 'auto', $unescapeslashquot=false)
Convert a SQL request in Mysql syntax to native syntax.
getListOfCollation()
Return list of available collation that can be used for database.
DDLCreateDb($database, $charset= '', $collation= '', $owner= '')
Create a new database Do not use function xxx_create_db (xxx=mysql, ...) as they are deprecated We fo...
decrypt($value)
Decrypt sensitive data in database.
query($query, $usesavepoint=0, $type= 'auto')
Convert request to PostgreSQL syntax, execute it and return the resultset.
lastquery()
Return last request executed with query()
getPathOfDump()
Return full path of dump program.
Class to manage Dolibarr database access.
DDLDropTable($table)
Drop a table into database.
select_db($database)
Select a database Ici postgresql n&#39;a aucune fonction equivalente de mysql_select_db On compare juste ...
Class to drive a Postgresql database for Dolibarr.
Definition: pgsql.class.php:36
last_insert_id($tab, $fieldid= 'rowid')
Get last ID after an insert INSERT.
getVersion()
Return version of database server.
lasterror()
Return last error label.
$type
Database type.
Definition: pgsql.class.php:39
$conf db
API class for accounts.
Definition: inc.php:54
fetch_array($resultset)
Return datas as an array.
DDLInfoTable($table)
List information of columns into a table.
escape($stringtoencode)
Escape a string to insert data.
free($resultset=null)
Libere le dernier resultset utilise sur cette connexion.
fetch_row($resultset)
Return datas as an array.
DDLDescTable($table, $field="")
Return a pointer of line with description of a table or field.
DDLAddField($table, $field_name, $field_desc, $field_position="")
Create a new field into table.
close()
Close database connexion.
fetch_object($resultset)
Renvoie la ligne courante (comme un objet) pour le curseur resultset.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename= '', $restricttologhandler= '', $logcontext=null)
Write log message into outputs.
DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
Create a user to connect to database.
getDriverInfo()
Return version of database client driver.
DDLDropField($table, $field_name)
Drop a field from table.
connect($host, $login, $passwd, $name, $port=0)
Connexion to server.
getDefaultCollationDatabase()
Return collation used in database.
error()
Renvoie le texte de l&#39;erreur pgsql de l&#39;operation precedente.
DDLListTables($database, $table= '')
List tables into a database.
getServerParametersValues($filter= '')
Return value of server parameters.
print
Draft customers invoices.
Definition: index.php:89
getDefaultCharacterSetDatabase()
Return charset used to store data in database.
num_rows($resultset)
Return number of lines for result of a SELECT.
ifsql($test, $resok, $resko)
Format a SQL IF.
if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) if(!empty($conf->don->enabled)&&$user->rights->don->lire) if(!empty($conf->tax->enabled)&&$user->rights->tax->charges->lire) if(!empty($conf->facture->enabled)&&!empty($conf->commande->enabled)&&$user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) if(!empty($conf->facture->enabled)&&$user->rights->facture->lire) if((!empty($conf->fournisseur->enabled)&&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)||!empty($conf->supplier_invoice->enabled))&&$user->rights->fournisseur->facture->lire) $resql
Social contributions to pay.
Definition: index.php:1232
plimit($limit=0, $offset=0)
Define limits and offset of request.
const VERSIONMIN
Version min database.
Definition: pgsql.class.php:47
$forcecollate
Collate used to force collate when creating database.
Definition: pgsql.class.php:45
getServerStatusValues($filter= '')
Return value of server status.
getListOfCharacterSet()
Return list of available charset that can be used to store data in database.
__construct($type, $host, $user, $pass, $name= '', $port=0)
Constructor.
Definition: pgsql.class.php:65
lasterrno()
Return last error code.
DDLGetConnectId()
Return connexion ID.
getPathOfRestore()
Return full path of restore program.
const LABEL
Database label.
Definition: pgsql.class.php:41
errno()
Renvoie le code erreur generique de l&#39;operation precedente.
encrypt($fieldorvalue, $withQuotes=0)
Encrypt sensitive data in database Warning: This function includes the escape, so it must use direct ...
$forcecharset
Charset.
Definition: pgsql.class.php:43