dolibarr 19.0.3
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
31require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
32
36class DoliDBPgsql extends DoliDB
37{
39 public $type = 'pgsql'; // Name of manager
40
42 const LABEL = 'PostgreSQL'; // Label of manager
43
45 public $forcecharset = 'UTF8'; // Can't be static as it may be forced with a dynamic value
46
48 public $forcecollate = ''; // Can't be static as it may be forced with a dynamic value
49
51 const VERSIONMIN = '9.0.0'; // Version min database
52
56 public $unescapeslashquot = false;
60 public $standard_conforming_strings = false;
61
62
64 private $_results;
65
66
67
79 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
80 {
81 global $conf, $langs;
82
83 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
84 if (!empty($conf->db->character_set)) {
85 $this->forcecharset = $conf->db->character_set;
86 }
87 if (!empty($conf->db->dolibarr_main_db_collation)) {
88 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
89 }
90
91 $this->database_user = $user;
92 $this->database_host = $host;
93 $this->database_port = $port;
94
95 $this->transaction_opened = 0;
96
97 //print "Name DB: $host,$user,$pass,$name<br>";
98
99 if (!function_exists("pg_connect")) {
100 $this->connected = false;
101 $this->ok = false;
102 $this->error = "Pgsql PHP functions are not available in this version of PHP";
103 dol_syslog(get_class($this)."::DoliDBPgsql : Pgsql PHP functions are not available in this version of PHP", LOG_ERR);
104 return;
105 }
106
107 if (!$host) {
108 $this->connected = false;
109 $this->ok = false;
110 $this->error = $langs->trans("ErrorWrongHostParameter");
111 dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect, wrong host parameters", LOG_ERR);
112 return;
113 }
114
115 // Essai connexion serveur
116 //print "$host, $user, $pass, $name, $port";
117 $this->db = $this->connect($host, $user, $pass, $name, $port);
118
119 if ($this->db) {
120 $this->connected = true;
121 $this->ok = true;
122 } else {
123 // host, login ou password incorrect
124 $this->connected = false;
125 $this->ok = false;
126 $this->error = 'Host, login or password incorrect';
127 dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Connect ".$this->error.'. Failed to connect to host='.$host.' port='.$port.' user='.$user, LOG_ERR);
128 }
129
130 // Si connexion serveur ok et si connexion base demandee, on essaie connexion base
131 if ($this->connected && $name) {
132 if ($this->select_db($name)) {
133 $this->database_selected = true;
134 $this->database_name = $name;
135 $this->ok = true;
136 } else {
137 $this->database_selected = false;
138 $this->database_name = '';
139 $this->ok = false;
140 $this->error = $this->error();
141 dol_syslog(get_class($this)."::DoliDBPgsql : Erreur Select_db ".$this->error, LOG_ERR);
142 }
143 } else {
144 // Pas de selection de base demandee, ok ou ko
145 $this->database_selected = false;
146 }
147 }
148
149
158 public function convertSQLFromMysql($line, $type = 'auto', $unescapeslashquot = false)
159 {
160 global $conf;
161
162 // Removed empty line if this is a comment line for SVN tagging
163 if (preg_match('/^--\s\$Id/i', $line)) {
164 return '';
165 }
166 // Return line if this is a comment
167 if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
168 return $line;
169 }
170 if ($line != "") {
171 // group_concat support (PgSQL >= 9.0)
172 // Replace group_concat(x) or group_concat(x SEPARATOR ',') with string_agg(x, ',')
173 $line = preg_replace('/GROUP_CONCAT/i', 'STRING_AGG', $line);
174 $line = preg_replace('/ SEPARATOR/i', ',', $line);
175 $line = preg_replace('/STRING_AGG\‍(([^,\‍)]+)\‍)/i', 'STRING_AGG(\\1, \',\')', $line);
176 //print $line."\n";
177
178 if ($type == 'auto') {
179 if (preg_match('/ALTER TABLE/i', $line)) {
180 $type = 'dml';
181 } elseif (preg_match('/CREATE TABLE/i', $line)) {
182 $type = 'dml';
183 } elseif (preg_match('/DROP TABLE/i', $line)) {
184 $type = 'dml';
185 }
186 }
187
188 $line = preg_replace('/ as signed\‍)/i', ' as integer)', $line);
189
190 if ($type == 'dml') {
191 $reg = array();
192
193 $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
194
195 // we are inside create table statement so lets process datatypes
196 if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
197 $line = preg_replace('/\‍)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i', ');', $line);
198 $line = preg_replace('/\‍)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i', ');', $line);
199 $line = preg_replace('/,$/', '', $line);
200 }
201
202 // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
203 if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
204 $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 SERIAL PRIMARY KEY', $line);
205 //$line = "-- ".$line." replaced by --\n".$newline;
206 $line = $newline;
207 }
208
209 if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+bigint.*auto_increment/i', $line, $reg)) {
210 $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+bigint.*auto_increment[^,]*/i', '\\1 \\2 BIGSERIAL PRIMARY KEY', $line);
211 //$line = "-- ".$line." replaced by --\n".$newline;
212 $line = $newline;
213 }
214
215 // tinyint type conversion
216 $line = preg_replace('/tinyint\‍(?[0-9]*\‍)?/', 'smallint', $line);
217 $line = preg_replace('/tinyint/i', 'smallint', $line);
218
219 // nuke unsigned
220 $line = preg_replace('/(int\w+|smallint|bigint)\s+unsigned/i', '\\1', $line);
221
222 // blob -> text
223 $line = preg_replace('/\w*blob/i', 'text', $line);
224
225 // tinytext/mediumtext -> text
226 $line = preg_replace('/tinytext/i', 'text', $line);
227 $line = preg_replace('/mediumtext/i', 'text', $line);
228 $line = preg_replace('/longtext/i', 'text', $line);
229
230 $line = preg_replace('/text\‍([0-9]+\‍)/i', 'text', $line);
231
232 // change not null datetime field to null valid ones
233 // (to support remapping of "zero time" to null
234 $line = preg_replace('/datetime not null/i', 'datetime', $line);
235 $line = preg_replace('/datetime/i', 'timestamp', $line);
236
237 // double -> numeric
238 $line = preg_replace('/^double/i', 'numeric', $line);
239 $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
240 // float -> numeric
241 $line = preg_replace('/^float/i', 'numeric', $line);
242 $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
243
244 //Check tms timestamp field case (in Mysql this field is defautled to now and
245 // on update defaulted by now
246 $line = preg_replace('/(\s*)tms(\s*)timestamp/i', '\\1tms timestamp without time zone DEFAULT now() NOT NULL', $line);
247
248 // nuke DEFAULT CURRENT_TIMESTAMP
249 $line = preg_replace('/(\s*)DEFAULT(\s*)CURRENT_TIMESTAMP/i', '\\1', $line);
250
251 // nuke ON UPDATE CURRENT_TIMESTAMP
252 $line = preg_replace('/(\s*)ON(\s*)UPDATE(\s*)CURRENT_TIMESTAMP/i', '\\1', $line);
253
254 // unique index(field1,field2)
255 if (preg_match('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', $line)) {
256 $line = preg_replace('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', 'UNIQUE\‍(\\1\‍)', $line);
257 }
258
259 // We remove end of requests "AFTER fieldxxx"
260 $line = preg_replace('/\sAFTER [a-z0-9_]+/i', '', $line);
261
262 // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
263 $line = preg_replace('/ALTER TABLE [a-z0-9_]+\s+DROP INDEX/i', 'DROP INDEX', $line);
264
265 // Translate order to rename fields
266 if (preg_match('/ALTER TABLE ([a-z0-9_]+)\s+CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
267 $line = "-- ".$line." replaced by --\n";
268 $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
269 }
270
271 // Translate order to modify field format
272 if (preg_match('/ALTER TABLE ([a-z0-9_]+)\s+MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
273 $line = "-- ".$line." replaced by --\n";
274 $newreg3 = $reg[3];
275 $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
276 $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
277 $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
278 $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
279 $newreg3 = preg_replace('/ DEFAULT \'?[0-9a-zA-Z_@]*\'?/i', '', $newreg3);
280 $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
281 // TODO Add alter to set default value or null/not null if there is this in $reg[3]
282 }
283
284 // alter table add primary key (field1, field2 ...) -> We remove the primary key name not accepted by PostGreSQL
285 // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity)
286 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\‍((.*)$/i', $line, $reg)) {
287 $line = "-- ".$line." replaced by --\n";
288 $line .= "ALTER TABLE ".$reg[1]." ADD PRIMARY KEY (".$reg[3];
289 }
290
291 // Translate order to drop primary keys
292 // ALTER TABLE llx_dolibarr_modules DROP PRIMARY KEY pk_xxx
293 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+PRIMARY\s+KEY\s*([^;]+)$/i', $line, $reg)) {
294 $line = "-- ".$line." replaced by --\n";
295 $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
296 }
297
298 // Translate order to drop foreign keys
299 // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx
300 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
301 $line = "-- ".$line." replaced by --\n";
302 $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
303 }
304
305 // Translate order to add foreign keys
306 // ALTER TABLE llx_tablechild ADD CONSTRAINT fk_tablechild_fk_fieldparent FOREIGN KEY (fk_fieldparent) REFERENCES llx_tableparent (rowid)
307 if (preg_match('/ALTER\s+TABLE\s+(.*)\s*ADD CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
308 $line = preg_replace('/;$/', '', $line);
309 $line .= " DEFERRABLE INITIALLY IMMEDIATE;";
310 }
311
312 // alter table add [unique] [index] (field1, field2 ...)
313 // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
314 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
315 $fieldlist = $reg[4];
316 $idxname = $reg[3];
317 $tablename = $reg[1];
318 $line = "-- ".$line." replaced by --\n";
319 $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
320 }
321 }
322
323 // To have postgresql case sensitive
324 $count_like = 0;
325 $line = str_replace(' LIKE \'', ' ILIKE \'', $line, $count_like);
326 if (getDolGlobalString('PSQL_USE_UNACCENT') && $count_like > 0) {
327 // @see https://docs.postgresql.fr/11/unaccent.html : 'unaccent()' function must be installed before
328 $line = preg_replace('/\s+(\‍(+\s*)([a-zA-Z0-9\-\_\.]+) ILIKE /', ' \1unaccent(\2) ILIKE ', $line);
329 }
330
331 $line = str_replace(' LIKE BINARY \'', ' LIKE \'', $line);
332
333 // Replace INSERT IGNORE into INSERT
334 $line = preg_replace('/^INSERT IGNORE/', 'INSERT', $line);
335
336 // Delete using criteria on other table must not declare twice the deleted table
337 // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
338 if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
339 if ($reg[1] == $reg[2]) { // If same table, we remove second one
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) {
369 $line = preg_replace("/\\\'/", "''", $line);
370 }
371
372 //print "type=".$type." newline=".$line."<br>\n";
373 }
374
375 return $line;
376 }
377
378 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
387 public function select_db($database)
388 {
389 // phpcs:enable
390 if ($database == $this->database_name) {
391 return true;
392 } else {
393 return false;
394 }
395 }
396
408 public function connect($host, $login, $passwd, $name, $port = 0)
409 {
410 // use pg_pconnect() instead of pg_connect() if you want to use persistent connection costing 1ms, instead of 30ms for non persistent
411
412 $this->db = false;
413
414 // connections parameters must be protected (only \ and ' according to pg_connect() manual)
415 $host = str_replace(array("\\", "'"), array("\\\\", "\\'"), $host);
416 $login = str_replace(array("\\", "'"), array("\\\\", "\\'"), $login);
417 $passwd = str_replace(array("\\", "'"), array("\\\\", "\\'"), $passwd);
418 $name = str_replace(array("\\", "'"), array("\\\\", "\\'"), $name);
419 $port = str_replace(array("\\", "'"), array("\\\\", "\\'"), $port);
420
421 if (!$name) {
422 $name = "postgres"; // When try to connect using admin user
423 }
424
425 // try first Unix domain socket (local)
426 if ((!empty($host) && $host == "socket") && !defined('NOLOCALSOCKETPGCONNECT')) {
427 $con_string = "dbname='".$name."' user='".$login."' password='".$passwd."'"; // $name may be empty
428 try {
429 $this->db = @pg_connect($con_string);
430 } catch (Exception $e) {
431 // No message
432 }
433 }
434
435 // if local connection failed or not requested, use TCP/IP
436 if (empty($this->db)) {
437 if (!$host) {
438 $host = "localhost";
439 }
440 if (!$port) {
441 $port = 5432;
442 }
443
444 $con_string = "host='".$host."' port='".$port."' dbname='".$name."' user='".$login."' password='".$passwd."'";
445 try {
446 $this->db = @pg_connect($con_string);
447 } catch (Exception $e) {
448 print $e->getMessage();
449 }
450 }
451
452 // now we test if at least one connect method was a success
453 if ($this->db) {
454 $this->database_name = $name;
455 pg_set_error_verbosity($this->db, PGSQL_ERRORS_VERBOSE); // Set verbosity to max
456 pg_query($this->db, "set datestyle = 'ISO, YMD';");
457 }
458
459 return $this->db;
460 }
461
467 public function getVersion()
468 {
469 $resql = $this->query('SHOW server_version');
470 if ($resql) {
471 $liste = $this->fetch_array($resql);
472 return $liste['server_version'];
473 }
474 return '';
475 }
476
482 public function getDriverInfo()
483 {
484 return 'pgsql php driver';
485 }
486
493 public function close()
494 {
495 if ($this->db) {
496 if ($this->transaction_opened > 0) {
497 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
498 }
499 $this->connected = false;
500 return pg_close($this->db);
501 }
502 return false;
503 }
504
514 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
515 {
516 global $conf, $dolibarr_main_db_readonly;
517
518 $query = trim($query);
519
520 // Convert MySQL syntax to PostgresSQL syntax
521 $query = $this->convertSQLFromMysql($query, $type, ($this->unescapeslashquot && $this->standard_conforming_strings));
522 //print "After convertSQLFromMysql:\n".$query."<br>\n";
523
524 if (getDolGlobalString('MAIN_DB_AUTOFIX_BAD_SQL_REQUEST')) {
525 // Fix bad formed requests. If request contains a date without quotes, we fix this but this should not occurs.
526 $loop = true;
527 while ($loop) {
528 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)) {
529 $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);
530 dol_syslog("Warning: Bad formed request converted into ".$query, LOG_WARNING);
531 } else {
532 $loop = false;
533 }
534 }
535 }
536
537 if ($usesavepoint && $this->transaction_opened) {
538 @pg_query($this->db, 'SAVEPOINT mysavepoint');
539 }
540
541 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
542 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
543 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
544 }
545 if (empty($query)) {
546 return false; // Return false = error if empty request
547 }
548
549 if (!empty($dolibarr_main_db_readonly)) {
550 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
551 $this->lasterror = 'Application in read-only mode';
552 $this->lasterrno = 'APPREADONLY';
553 $this->lastquery = $query;
554 return false;
555 }
556 }
557
558 $ret = @pg_query($this->db, $query);
559
560 //print $query;
561 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) { // Si requete utilisateur, on la sauvegarde ainsi que son resultset
562 if (!$ret) {
563 if ($this->errno() != 'DB_ERROR_25P02') { // Do not overwrite errors if this is a consecutive error
564 $this->lastqueryerror = $query;
565 $this->lasterror = $this->error();
566 $this->lasterrno = $this->errno();
567
568 if (getDolGlobalInt('SYSLOG_LEVEL') < LOG_DEBUG) {
569 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
570 }
571 dol_syslog(get_class($this)."::query SQL Error message: ".$this->lasterror." (".$this->lasterrno.")", LOG_ERR);
572 dol_syslog(get_class($this)."::query SQL Error usesavepoint = ".$usesavepoint, LOG_ERR);
573 }
574
575 if ($usesavepoint && $this->transaction_opened) { // Warning, after that errno will be erased
576 @pg_query($this->db, 'ROLLBACK TO SAVEPOINT mysavepoint');
577 }
578 }
579 $this->lastquery = $query;
580 $this->_results = $ret;
581 }
582
583 return $ret;
584 }
585
586 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
593 public function fetch_object($resultset)
594 {
595 // phpcs:enable
596 // If resultset not provided, we take the last used by connexion
597 if (!is_resource($resultset) && !is_object($resultset)) {
598 $resultset = $this->_results;
599 }
600 return pg_fetch_object($resultset);
601 }
602
603 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
610 public function fetch_array($resultset)
611 {
612 // phpcs:enable
613 // If resultset not provided, we take the last used by connexion
614 if (!is_resource($resultset) && !is_object($resultset)) {
615 $resultset = $this->_results;
616 }
617 return pg_fetch_array($resultset);
618 }
619
620 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
627 public function fetch_row($resultset)
628 {
629 // phpcs:enable
630 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
631 if (!is_resource($resultset) && !is_object($resultset)) {
632 $resultset = $this->_results;
633 }
634 return pg_fetch_row($resultset);
635 }
636
637 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
645 public function num_rows($resultset)
646 {
647 // phpcs:enable
648 // If resultset not provided, we take the last used by connexion
649 if (!is_resource($resultset) && !is_object($resultset)) {
650 $resultset = $this->_results;
651 }
652 return pg_num_rows($resultset);
653 }
654
655 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
663 public function affected_rows($resultset)
664 {
665 // phpcs:enable
666 // If resultset not provided, we take the last used by connexion
667 if (!is_resource($resultset) && !is_object($resultset)) {
668 $resultset = $this->_results;
669 }
670 // pgsql necessite un resultset pour cette fonction contrairement
671 // a mysql qui prend un link de base
672 return pg_affected_rows($resultset);
673 }
674
675
682 public function free($resultset = null)
683 {
684 // If resultset not provided, we take the last used by connexion
685 if (!is_resource($resultset) && !is_object($resultset)) {
686 $resultset = $this->_results;
687 }
688 // Si resultset en est un, on libere la memoire
689 if (is_resource($resultset) || is_object($resultset)) {
690 pg_free_result($resultset);
691 }
692 }
693
694
702 public function plimit($limit = 0, $offset = 0)
703 {
704 global $conf;
705 if (empty($limit)) {
706 return "";
707 }
708 if ($limit < 0) {
709 $limit = $conf->liste_limit;
710 }
711 if ($offset > 0) {
712 return " LIMIT ".$limit." OFFSET ".$offset." ";
713 } else {
714 return " LIMIT $limit ";
715 }
716 }
717
718
725 public function escape($stringtoencode)
726 {
727 return pg_escape_string($stringtoencode);
728 }
729
736 public function escapeforlike($stringtoencode)
737 {
738 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
739 }
740
749 public function ifsql($test, $resok, $resko)
750 {
751 return '(CASE WHEN '.$test.' THEN '.$resok.' ELSE '.$resko.' END)';
752 }
753
762 public function regexpsql($subject, $pattern, $sqlstring = 0)
763 {
764 if ($sqlstring) {
765 return "(". $subject ." ~ '" . $pattern . "')";
766 }
767
768 return "('". $subject ."' ~ '" . $pattern . "')";
769 }
770
771
777 public function errno()
778 {
779 if (!$this->connected) {
780 // Si il y a eu echec de connexion, $this->db n'est pas valide.
781 return 'DB_ERROR_FAILED_TO_CONNECT';
782 } else {
783 // Constants to convert error code to a generic Dolibarr error code
784 $errorcode_map = array(
785 1004 => 'DB_ERROR_CANNOT_CREATE',
786 1005 => 'DB_ERROR_CANNOT_CREATE',
787 1006 => 'DB_ERROR_CANNOT_CREATE',
788 1007 => 'DB_ERROR_ALREADY_EXISTS',
789 1008 => 'DB_ERROR_CANNOT_DROP',
790 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
791 1044 => 'DB_ERROR_ACCESSDENIED',
792 1046 => 'DB_ERROR_NODBSELECTED',
793 1048 => 'DB_ERROR_CONSTRAINT',
794 '42P07' => 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS',
795 '42703' => 'DB_ERROR_NOSUCHFIELD',
796 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
797 42701=> 'DB_ERROR_COLUMN_ALREADY_EXISTS',
798 '42710' => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
799 '23505' => 'DB_ERROR_RECORD_ALREADY_EXISTS',
800 '42704' => 'DB_ERROR_NO_INDEX_TO_DROP', // May also be Type xxx does not exists
801 '42601' => 'DB_ERROR_SYNTAX',
802 '42P16' => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
803 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
804 1091 => 'DB_ERROR_NOSUCHFIELD',
805 1100 => 'DB_ERROR_NOT_LOCKED',
806 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
807 '42P01' => 'DB_ERROR_NOSUCHTABLE',
808 '23503' => 'DB_ERROR_NO_PARENT',
809 1217 => 'DB_ERROR_CHILD_EXISTS',
810 1451 => 'DB_ERROR_CHILD_EXISTS',
811 '42P04' => 'DB_DATABASE_ALREADY_EXISTS'
812 );
813
814 $errorlabel = pg_last_error($this->db);
815 $errorcode = '';
816 $reg = array();
817 if (preg_match('/: *([0-9P]+):/', $errorlabel, $reg)) {
818 $errorcode = $reg[1];
819 if (isset($errorcode_map[$errorcode])) {
820 return $errorcode_map[$errorcode];
821 }
822 }
823 $errno = $errorcode ? $errorcode : $errorlabel;
824 return ($errno ? 'DB_ERROR_'.$errno : '0');
825 }
826 // '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => 'DB_ERROR_NOSUCHTABLE',
827 // '/table [\"\'].*[\"\'] does not exist/' => 'DB_ERROR_NOSUCHTABLE',
828 // '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => 'DB_ERROR_RECORD_ALREADY_EXISTS',
829 // '/divide by zero$/' => 'DB_ERROR_DIVZERO',
830 // '/pg_atoi: error in .*: can\'t parse /' => 'DB_ERROR_INVALID_NUMBER',
831 // '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => 'DB_ERROR_NOSUCHFIELD',
832 // '/parser: parse error at or near \"/' => 'DB_ERROR_SYNTAX',
833 // '/referential integrity violation/' => 'DB_ERROR_CONSTRAINT'
834 }
835
841 public function error()
842 {
843 return pg_last_error($this->db);
844 }
845
846 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
854 public function last_insert_id($tab, $fieldid = 'rowid')
855 {
856 // phpcs:enable
857 //$result = pg_query($this->db,"SELECT MAX(".$fieldid.") FROM ".$tab);
858 $result = pg_query($this->db, "SELECT currval('".$tab."_".$fieldid."_seq')");
859 if (!$result) {
860 print pg_last_error($this->db);
861 exit;
862 }
863 //$nbre = pg_num_rows($result);
864 $row = pg_fetch_result($result, 0, 0);
865 return $row;
866 }
867
876 public function encrypt($fieldorvalue, $withQuotes = 1)
877 {
878 global $conf;
879
880 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
881 //$cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
882
883 //Encryption key
884 //$cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
885
886 $return = $fieldorvalue;
887 return ($withQuotes ? "'" : "").$this->escape($return).($withQuotes ? "'" : "");
888 }
889
890
897 public function decrypt($value)
898 {
899 global $conf;
900
901 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
902 //$cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
903
904 //Encryption key
905 //$cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
906
907 $return = $value;
908 return $return;
909 }
910
911
912 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
918 public function DDLGetConnectId()
919 {
920 // phpcs:enable
921 return '?';
922 }
923
924
925
926 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
938 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
939 {
940 // phpcs:enable
941 if (empty($charset)) {
942 $charset = $this->forcecharset;
943 }
944 if (empty($collation)) {
945 $collation = $this->forcecollate;
946 }
947
948 // Test charset match LC_TYPE (pgsql error otherwise)
949 //print $charset.' '.setlocale(LC_CTYPE,'0'); exit;
950
951 // NOTE: Do not use ' around the database name
952 $sql = "CREATE DATABASE ".$this->escape($database)." OWNER '".$this->escape($owner)."' ENCODING '".$this->escape($charset)."'";
953 dol_syslog($sql, LOG_DEBUG);
954 $ret = $this->query($sql);
955 return $ret;
956 }
957
958 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
966 public function DDLListTables($database, $table = '')
967 {
968 // phpcs:enable
969 $listtables = array();
970
971 $escapedlike = '';
972 if ($table) {
973 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
974
975 $escapedlike = " AND table_name LIKE '".$this->escape($tmptable)."'";
976 }
977 $result = pg_query($this->db, "SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'".$escapedlike." ORDER BY table_name");
978 if ($result) {
979 while ($row = $this->fetch_row($result)) {
980 $listtables[] = $row[0];
981 }
982 }
983 return $listtables;
984 }
985
986 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
994 public function DDLListTablesFull($database, $table = '')
995 {
996 // phpcs:enable
997 $listtables = array();
998
999 $escapedlike = '';
1000 if ($table) {
1001 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
1002
1003 $escapedlike = " AND table_name LIKE '".$this->escape($tmptable)."'";
1004 }
1005 $result = pg_query($this->db, "SELECT table_name, table_type FROM information_schema.tables WHERE table_schema = 'public'".$escapedlike." ORDER BY table_name");
1006 if ($result) {
1007 while ($row = $this->fetch_row($result)) {
1008 $listtables[] = $row;
1009 }
1010 }
1011 return $listtables;
1012 }
1013
1014 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1022 public function DDLInfoTable($table)
1023 {
1024 // phpcs:enable
1025 $infotables = array();
1026
1027 $sql = "SELECT ";
1028 $sql .= " infcol.column_name as \"Column\",";
1029 $sql .= " CASE WHEN infcol.character_maximum_length IS NOT NULL THEN infcol.udt_name || '('||infcol.character_maximum_length||')'";
1030 $sql .= " ELSE infcol.udt_name";
1031 $sql .= " END as \"Type\",";
1032 $sql .= " infcol.collation_name as \"Collation\",";
1033 $sql .= " infcol.is_nullable as \"Null\",";
1034 $sql .= " '' as \"Key\",";
1035 $sql .= " infcol.column_default as \"Default\",";
1036 $sql .= " '' as \"Extra\",";
1037 $sql .= " '' as \"Privileges\"";
1038 $sql .= " FROM information_schema.columns infcol";
1039 $sql .= " WHERE table_schema = 'public' ";
1040 $sql .= " AND table_name = '".$this->escape($table)."'";
1041 $sql .= " ORDER BY ordinal_position;";
1042
1043 dol_syslog($sql, LOG_DEBUG);
1044 $result = $this->query($sql);
1045 if ($result) {
1046 while ($row = $this->fetch_row($result)) {
1047 $infotables[] = $row;
1048 }
1049 }
1050 return $infotables;
1051 }
1052
1053
1054 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1067 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
1068 {
1069 // phpcs:enable
1070 // FIXME: $fulltext_keys parameter is unused
1071
1072 // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
1073 // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1074 $sql = "create table ".$table."(";
1075 $i = 0;
1076 foreach ($fields as $field_name => $field_desc) {
1077 $sqlfields[$i] = $field_name." ";
1078 $sqlfields[$i] .= $field_desc['type'];
1079 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1080 $sqlfields[$i] .= "(".$field_desc['value'].")";
1081 } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1082 $sqlfields[$i] .= " ".$field_desc['attribute'];
1083 } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
1084 if (preg_match("/null/i", $field_desc['default'])) {
1085 $sqlfields[$i] .= " default ".$field_desc['default'];
1086 } else {
1087 $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
1088 }
1089 } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
1090 $sqlfields[$i] .= " ".$field_desc['null'];
1091 } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1092 $sqlfields[$i] .= " ".$field_desc['extra'];
1093 }
1094 $i++;
1095 }
1096 if ($primary_key != "") {
1097 $pk = "primary key(".$primary_key.")";
1098 }
1099
1100 if (is_array($unique_keys)) {
1101 $i = 0;
1102 foreach ($unique_keys as $key => $value) {
1103 $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
1104 $i++;
1105 }
1106 }
1107 if (is_array($keys)) {
1108 $i = 0;
1109 foreach ($keys as $key => $value) {
1110 $sqlk[$i] = "KEY ".$key." (".$value.")";
1111 $i++;
1112 }
1113 }
1114 $sql .= implode(',', $sqlfields);
1115 if ($primary_key != "") {
1116 $sql .= ",".$pk;
1117 }
1118 if (is_array($unique_keys)) {
1119 $sql .= ",".implode(',', $sqluq);
1120 }
1121 if (is_array($keys)) {
1122 $sql .= ",".implode(',', $sqlk);
1123 }
1124 $sql .= ") type=".$type;
1125
1126 dol_syslog($sql, LOG_DEBUG);
1127 if (!$this->query($sql)) {
1128 return -1;
1129 } else {
1130 return 1;
1131 }
1132 }
1133
1134 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1141 public function DDLDropTable($table)
1142 {
1143 // phpcs:enable
1144 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1145
1146 $sql = "DROP TABLE ".$tmptable;
1147
1148 if (!$this->query($sql)) {
1149 return -1;
1150 } else {
1151 return 1;
1152 }
1153 }
1154
1155 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1165 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1166 {
1167 // phpcs:enable
1168 // Note: using ' on user does not works with pgsql
1169 $sql = "CREATE USER ".$this->escape($dolibarr_main_db_user)." with password '".$this->escape($dolibarr_main_db_pass)."'";
1170
1171 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1172 $resql = $this->query($sql);
1173 if (!$resql) {
1174 return -1;
1175 }
1176
1177 return 1;
1178 }
1179
1180 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1188 public function DDLDescTable($table, $field = "")
1189 {
1190 // phpcs:enable
1191 $sql = "SELECT attname FROM pg_attribute, pg_type WHERE typname = '".$this->escape($table)."' AND attrelid = typrelid";
1192 $sql .= " AND attname NOT IN ('cmin', 'cmax', 'ctid', 'oid', 'tableoid', 'xmin', 'xmax')";
1193 if ($field) {
1194 $sql .= " AND attname = '".$this->escape($field)."'";
1195 }
1196
1197 dol_syslog($sql, LOG_DEBUG);
1198 $this->_results = $this->query($sql);
1199 return $this->_results;
1200 }
1201
1202 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1212 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1213 {
1214 // phpcs:enable
1215 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1216 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1217 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1218 $sql .= $field_desc['type'];
1219 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1220 if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
1221 $sql .= "(".$field_desc['value'].")";
1222 }
1223 }
1224 if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1225 $sql .= " ".$field_desc['attribute'];
1226 }
1227 if (preg_match("/^[^\s]/i", $field_desc['null'])) {
1228 $sql .= " ".$field_desc['null'];
1229 }
1230 if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1231 if (preg_match("/null/i", $field_desc['default'])) {
1232 $sql .= " default ".$field_desc['default'];
1233 } else {
1234 $sql .= " default '".$this->escape($field_desc['default'])."'";
1235 }
1236 }
1237 if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1238 $sql .= " ".$field_desc['extra'];
1239 }
1240 $sql .= " ".$field_position;
1241
1242 dol_syslog($sql, LOG_DEBUG);
1243 if (!$this -> query($sql)) {
1244 return -1;
1245 }
1246 return 1;
1247 }
1248
1249 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1258 public function DDLUpdateField($table, $field_name, $field_desc)
1259 {
1260 // phpcs:enable
1261 $sql = "ALTER TABLE ".$table;
1262 $sql .= " ALTER COLUMN ".$this->escape($field_name)." TYPE ".$field_desc['type'];
1263 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1264 if (!in_array($field_desc['type'], array('smallint', 'int', 'date', 'datetime')) && $field_desc['value']) {
1265 $sql .= "(".$field_desc['value'].")";
1266 }
1267 }
1268
1269 if ($field_desc['null'] == 'not null' || $field_desc['null'] == 'NOT NULL') {
1270 // 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
1271 if ($field_desc['type'] == 'varchar' || $field_desc['type'] == 'text') {
1272 $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = '".$this->escape(isset($field_desc['default']) ? $field_desc['default'] : '')."' WHERE ".$this->escape($field_name)." IS NULL";
1273 $this->query($sqlbis);
1274 } elseif ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
1275 $sqlbis = "UPDATE ".$table." SET ".$this->escape($field_name)." = ".((int) $this->escape(isset($field_desc['default']) ? $field_desc['default'] : 0))." WHERE ".$this->escape($field_name)." IS NULL";
1276 $this->query($sqlbis);
1277 }
1278 }
1279
1280 if (isset($field_desc['default']) && $field_desc['default'] != '') {
1281 if ($field_desc['type'] == 'double' || $field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int') {
1282 $sql .= ", ALTER COLUMN ".$this->escape($field_name)." SET DEFAULT ".((float) $field_desc['default']);
1283 } elseif ($field_desc['type'] != 'text') { // Default not supported on text fields ?
1284 $sql .= ", ALTER COLUMN ".$this->escape($field_name)." SET DEFAULT '".$this->escape($field_desc['default'])."'";
1285 }
1286 }
1287
1288 dol_syslog($sql, LOG_DEBUG);
1289 if (!$this->query($sql)) {
1290 return -1;
1291 }
1292 return 1;
1293 }
1294
1295 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1303 public function DDLDropField($table, $field_name)
1304 {
1305 // phpcs:enable
1306 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1307
1308 $sql = "ALTER TABLE ".$table." DROP COLUMN ".$tmp_field_name;
1309 if (!$this->query($sql)) {
1310 $this->error = $this->lasterror();
1311 return -1;
1312 }
1313 return 1;
1314 }
1315
1322 {
1323 $resql = $this->query('SHOW SERVER_ENCODING');
1324 if ($resql) {
1325 $liste = $this->fetch_array($resql);
1326 return $liste['server_encoding'];
1327 } else {
1328 return '';
1329 }
1330 }
1331
1337 public function getListOfCharacterSet()
1338 {
1339 $resql = $this->query('SHOW SERVER_ENCODING');
1340 $liste = array();
1341 if ($resql) {
1342 $i = 0;
1343 while ($obj = $this->fetch_object($resql)) {
1344 $liste[$i]['charset'] = $obj->server_encoding;
1345 $liste[$i]['description'] = 'Default database charset';
1346 $i++;
1347 }
1348 $this->free($resql);
1349 } else {
1350 return null;
1351 }
1352 return $liste;
1353 }
1354
1361 {
1362 $resql = $this->query('SHOW LC_COLLATE');
1363 if ($resql) {
1364 $liste = $this->fetch_array($resql);
1365 return $liste['lc_collate'];
1366 } else {
1367 return '';
1368 }
1369 }
1370
1376 public function getListOfCollation()
1377 {
1378 $resql = $this->query('SHOW LC_COLLATE');
1379 $liste = array();
1380 if ($resql) {
1381 $i = 0;
1382 while ($obj = $this->fetch_object($resql)) {
1383 $liste[$i]['collation'] = $obj->lc_collate;
1384 $i++;
1385 }
1386 $this->free($resql);
1387 } else {
1388 return null;
1389 }
1390 return $liste;
1391 }
1392
1398 public function getPathOfDump()
1399 {
1400 $fullpathofdump = '/pathtopgdump/pg_dump';
1401
1402 if (file_exists('/usr/bin/pg_dump')) {
1403 $fullpathofdump = '/usr/bin/pg_dump';
1404 } else {
1405 // TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
1406 $resql = $this->query('SHOW data_directory');
1407 if ($resql) {
1408 $liste = $this->fetch_array($resql);
1409 $basedir = $liste['data_directory'];
1410 $fullpathofdump = preg_replace('/data$/', 'bin', $basedir).'/pg_dump';
1411 }
1412 }
1413
1414 return $fullpathofdump;
1415 }
1416
1422 public function getPathOfRestore()
1423 {
1424 //$tool='pg_restore';
1425 $tool = 'psql';
1426
1427 $fullpathofdump = '/pathtopgrestore/'.$tool;
1428
1429 if (file_exists('/usr/bin/'.$tool)) {
1430 $fullpathofdump = '/usr/bin/'.$tool;
1431 } else {
1432 // TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
1433 $resql = $this->query('SHOW data_directory');
1434 if ($resql) {
1435 $liste = $this->fetch_array($resql);
1436 $basedir = $liste['data_directory'];
1437 $fullpathofdump = preg_replace('/data$/', 'bin', $basedir).'/'.$tool;
1438 }
1439 }
1440
1441 return $fullpathofdump;
1442 }
1443
1450 public function getServerParametersValues($filter = '')
1451 {
1452 $result = array();
1453
1454 $resql = 'select name,setting from pg_settings';
1455 if ($filter) {
1456 $resql .= " WHERE name = '".$this->escape($filter)."'";
1457 }
1458 $resql = $this->query($resql);
1459 if ($resql) {
1460 while ($obj = $this->fetch_object($resql)) {
1461 $result[$obj->name] = $obj->setting;
1462 }
1463 }
1464
1465 return $result;
1466 }
1467
1474 public function getServerStatusValues($filter = '')
1475 {
1476 /* This is to return current running requests.
1477 $sql='SELECT datname,procpid,current_query FROM pg_stat_activity ORDER BY procpid';
1478 if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1479 $resql=$this->query($sql);
1480 if ($resql)
1481 {
1482 $obj=$this->fetch_object($resql);
1483 $result[$obj->Variable_name]=$obj->Value;
1484 }
1485 */
1486
1487 return array();
1488 }
1489}
Class to manage Dolibarr database access.
lastqueryerror()
Return last query in error.
lasterror()
Return last error label.
lasterrno()
Return last error code.
lastquery()
Return last request executed with query()
Class to drive a Postgresql database for Dolibarr.
errno()
Renvoie le code erreur generique de l'operation precedente.
DDLListTablesFull($database, $table='')
List tables into a database.
DDLGetConnectId()
Return connexion ID.
num_rows($resultset)
Return number of lines for result of a SELECT.
const VERSIONMIN
Version min database.
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
Create a user to connect to database.
DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys=null, $fulltext_keys=null, $keys=null)
Create a table into database.
DDLDropTable($table)
Drop a table into database.
DDLUpdateField($table, $field_name, $field_desc)
Update format of a field into a table.
getPathOfDump()
Return full path of dump program.
select_db($database)
Select a database Ici postgresql n'a aucune fonction equivalente de mysql_select_db On compare juste ...
getServerStatusValues($filter='')
Return value of server status.
plimit($limit=0, $offset=0)
Define limits and offset of request.
decrypt($value)
Decrypt sensitive data in database.
error()
Renvoie le texte de l'erreur pgsql de l'operation precedente.
escape($stringtoencode)
Escape a string to insert data.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Convert request to PostgreSQL syntax, execute it and return the resultset.
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
close()
Close database connexion.
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
getListOfCharacterSet()
Return list of available charset that can be used to store data in database.
fetch_array($resultset)
Return datas as an array.
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
getPathOfRestore()
Return full path of restore program.
DDLAddField($table, $field_name, $field_desc, $field_position="")
Create a new field into table.
$type
Database type.
DDLInfoTable($table)
List information of columns into a table.
connect($host, $login, $passwd, $name, $port=0)
Connexion to server.
getVersion()
Return version of database server.
$forcecharset
Charset.
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
affected_rows($resultset)
Return the number of lines in the result of a request INSERT, DELETE or UPDATE.
DDLDropField($table, $field_name)
Drop a field from table.
regexpsql($subject, $pattern, $sqlstring=0)
Format a SQL REGEXP.
DDLCreateDb($database, $charset='', $collation='', $owner='')
Create a new database Do not use function xxx_create_db (xxx=mysql, ...) as they are deprecated We fo...
const LABEL
Database label.
getListOfCollation()
Return list of available collation that can be used for database.
getDriverInfo()
Return version of database client driver.
free($resultset=null)
Libere le dernier resultset utilise sur cette connexion.
DDLDescTable($table, $field="")
Return a pointer of line with description of a table or field.
ifsql($test, $resok, $resko)
Format a SQL IF.
getDefaultCollationDatabase()
Return collation used in database.
convertSQLFromMysql($line, $type='auto', $unescapeslashquot=false)
Convert a SQL request in Mysql syntax to native syntax.
getDefaultCharacterSetDatabase()
Return charset used to store data in database.
$forcecollate
Collate used to force collate when creating database.
fetch_row($resultset)
Return datas as an array.
getServerParametersValues($filter='')
Return value of server parameters.
DDLListTables($database, $table='')
List tables into a database.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.