2004-10-20 00:47:16 +02:00
< ? php
2012-01-06 09:31:02 +01:00
/* Copyright ( C ) 2001 Fabien Seisen < seisen @ linuxfr . org >
* Copyright ( C ) 2002 - 2005 Rodolphe Quiedeville < rodolphe @ quiedeville . org >
2014-08-15 19:29:19 +02:00
* Copyright ( C ) 2004 - 2014 Laurent Destailleur < eldy @ users . sourceforge . net >
2012-01-06 09:31:02 +01:00
* Copyright ( C ) 2004 Sebastien Di Cintio < sdicintio @ ressource - toi . org >
* Copyright ( C ) 2004 Benoit Mortier < benoit . mortier @ opensides . be >
2018-10-27 14:43:12 +02:00
* Copyright ( C ) 2005 - 2012 Regis Houssin < regis . houssin @ inodbox . com >
2012-01-06 09:31:02 +01:00
* Copyright ( C ) 2012 Yann Droneaud < yann @ droneaud . fr >
2012-12-08 14:23:52 +01:00
* Copyright ( C ) 2012 Florian Henry < florian . henry @ open - concept . pro >
2015-02-02 11:48:57 +01:00
* Copyright ( C ) 2015 Marcos García < marcosgdf @ gmail . com >
2004-08-24 09:02:32 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2013-01-16 15:36:08 +01:00
* the Free Software Foundation ; either version 3 of the License , or
2004-08-24 09:02:32 +02:00
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2019-09-23 21:55:30 +02:00
* along with this program . If not , see < https :// www . gnu . org / licenses />.
2004-08-24 09:02:32 +02:00
*/
2005-03-20 03:26:59 +01:00
/**
2011-10-24 18:40:28 +02:00
* \file htdocs / core / db / pgsql . class . php
2009-10-25 19:53:09 +01:00
* \brief Fichier de la classe permettant de gerer une base pgsql
2009-10-22 19:15:09 +02:00
*/
2004-08-24 09:02:32 +02:00
2020-04-10 10:59:32 +02:00
require_once DOL_DOCUMENT_ROOT . '/core/db/DoliDB.class.php' ;
2005-09-04 03:48:09 +02:00
2005-03-20 03:26:59 +01:00
/**
2013-02-21 21:04:20 +01:00
* Class to drive a Postgresql database for Dolibarr
2009-10-22 19:15:09 +02:00
*/
2013-09-10 12:29:55 +02:00
class DoliDBPgsql extends DoliDB
2004-09-02 22:28:56 +02:00
{
2020-10-31 14:32:18 +01:00
//! Database type
public $type = 'pgsql' ; // Name of manager
2021-01-25 12:29:31 +01:00
2020-10-31 14:32:18 +01:00
//! Database label
2020-04-10 10:59:32 +02:00
const LABEL = 'PostgreSQL' ; // Label of manager
2021-01-25 12:29:31 +01:00
2009-10-22 19:15:09 +02:00
//! Charset
2020-10-31 14:32:18 +01:00
public $forcecharset = 'UTF8' ; // Can't be static as it may be forced with a dynamic value
2021-01-25 12:29:31 +01:00
2020-10-31 14:32:18 +01:00
//! Collate used to force collate when creating database
public $forcecollate = '' ; // Can't be static as it may be forced with a dynamic value
2021-01-25 12:29:31 +01:00
2011-12-19 21:07:55 +01:00
//! Version min database
2020-04-10 10:59:32 +02:00
const VERSIONMIN = '9.0.0' ; // Version min database
2021-01-25 12:29:31 +01:00
/** @var resource|boolean Resultset of last query */
2012-02-15 13:55:00 +01:00
private $_results ;
2014-05-29 19:30:51 +02:00
2014-05-13 18:50:35 +02:00
public $unescapeslashquot ;
2014-05-13 18:54:57 +02:00
public $standard_conforming_strings ;
2006-06-24 22:58:22 +02:00
2021-01-25 12:29:31 +01:00
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Constructor .
* This create an opened connexion to a database server and eventually to a database
*
* @ param string $type Type of database ( mysql , pgsql ... )
* @ param string $host Address of database server
* @ param string $user Nom de l ' utilisateur autorise
* @ param string $pass Mot de passe
* @ param string $name Nom de la database
* @ param int $port Port of database server
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function __construct ( $type , $host , $user , $pass , $name = '' , $port = 0 )
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
global $conf , $langs ;
2007-07-13 14:57:07 +02:00
2020-10-31 14:32:18 +01:00
// Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
2021-02-23 22:03:23 +01:00
if ( ! empty ( $conf -> db -> character_set )) {
$this -> forcecharset = $conf -> db -> character_set ;
}
if ( ! empty ( $conf -> db -> dolibarr_main_db_collation )) {
$this -> forcecollate = $conf -> db -> dolibarr_main_db_collation ;
}
2012-04-28 18:04:55 +02:00
2020-04-10 10:59:32 +02:00
$this -> database_user = $user ;
2020-10-31 14:32:18 +01:00
$this -> database_host = $host ;
$this -> database_port = $port ;
2009-10-22 19:15:09 +02:00
2020-04-10 10:59:32 +02:00
$this -> transaction_opened = 0 ;
2009-10-22 19:15:09 +02:00
//print "Name DB: $host,$user,$pass,$name<br>";
2021-02-23 22:03:23 +01:00
if ( ! function_exists ( " pg_connect " )) {
2015-05-12 19:01:01 +02:00
$this -> connected = false ;
$this -> ok = false ;
2020-04-10 10:59:32 +02:00
$this -> error = " Pgsql PHP functions are not available in this version of PHP " ;
2019-01-27 11:55:16 +01:00
dol_syslog ( get_class ( $this ) . " ::DoliDBPgsql : Pgsql PHP functions are not available in this version of PHP " , LOG_ERR );
2009-10-22 19:15:09 +02:00
return $this -> ok ;
}
2021-02-23 22:03:23 +01:00
if ( ! $host ) {
2015-05-12 19:01:01 +02:00
$this -> connected = false ;
$this -> ok = false ;
2020-04-10 10:59:32 +02:00
$this -> error = $langs -> trans ( " ErrorWrongHostParameter " );
2019-01-27 11:55:16 +01:00
dol_syslog ( get_class ( $this ) . " ::DoliDBPgsql : Erreur Connect, wrong host parameters " , LOG_ERR );
2009-10-22 19:15:09 +02:00
return $this -> ok ;
}
// Essai connexion serveur
//print "$host, $user, $pass, $name, $port";
$this -> db = $this -> connect ( $host , $user , $pass , $name , $port );
2012-05-06 15:36:53 +02:00
2021-02-23 22:03:23 +01:00
if ( $this -> db ) {
2015-05-12 19:01:01 +02:00
$this -> connected = true ;
$this -> ok = true ;
2020-05-21 15:05:19 +02:00
} else {
2009-10-22 19:15:09 +02:00
// host, login ou password incorrect
2015-05-12 19:01:01 +02:00
$this -> connected = false ;
$this -> ok = false ;
2020-04-10 10:59:32 +02:00
$this -> error = 'Host, login or password incorrect' ;
2019-01-27 11:55:16 +01:00
dol_syslog ( get_class ( $this ) . " ::DoliDBPgsql : Erreur Connect " . $this -> error , LOG_ERR );
2009-10-22 19:15:09 +02:00
}
// Si connexion serveur ok et si connexion base demandee, on essaie connexion base
2021-02-23 22:03:23 +01:00
if ( $this -> connected && $name ) {
if ( $this -> select_db ( $name )) {
2015-05-12 19:01:01 +02:00
$this -> database_selected = true ;
2009-10-22 19:15:09 +02:00
$this -> database_name = $name ;
2015-05-12 19:01:01 +02:00
$this -> ok = true ;
2020-05-21 15:05:19 +02:00
} else {
2015-05-12 19:01:01 +02:00
$this -> database_selected = false ;
2009-10-22 19:15:09 +02:00
$this -> database_name = '' ;
2015-05-12 19:01:01 +02:00
$this -> ok = false ;
2020-04-10 10:59:32 +02:00
$this -> error = $this -> error ();
2019-01-27 11:55:16 +01:00
dol_syslog ( get_class ( $this ) . " ::DoliDBPgsql : Erreur Select_db " . $this -> error , LOG_ERR );
2009-10-22 19:15:09 +02:00
}
2020-05-21 15:05:19 +02:00
} else {
2009-10-22 19:15:09 +02:00
// Pas de selection de base demandee, ok ou ko
2015-05-12 19:01:01 +02:00
$this -> database_selected = false ;
2009-10-22 19:15:09 +02:00
}
return $this -> ok ;
}
2020-10-31 14:32:18 +01:00
/**
* Convert a SQL request in Mysql syntax to native syntax
*
* @ param string $line SQL request line to convert
* @ param string $type Type of SQL order ( 'ddl' for insert , update , select , delete or 'dml' for create , alter ... )
* @ param bool $unescapeslashquot Unescape slash quote with quote quote
* @ return string SQL request line converted
*/
2019-03-01 19:24:06 +01:00
public static function convertSQLFromMysql ( $line , $type = 'auto' , $unescapeslashquot = false )
2008-09-06 01:08:07 +02:00
{
2019-02-07 17:47:17 +01:00
global $conf ;
2019-02-08 11:26:08 +01:00
2011-09-20 12:30:56 +02:00
// Removed empty line if this is a comment line for SVN tagging
2019-01-27 11:55:16 +01:00
if ( preg_match ( '/^--\s\$Id/i' , $line )) {
2009-10-22 19:15:09 +02:00
return '' ;
2008-09-06 01:38:14 +02:00
}
2011-09-20 12:30:56 +02:00
// Return line if this is a comment
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/^#/i' , $line ) || preg_match ( '/^$/i' , $line ) || preg_match ( '/^--/i' , $line )) {
2009-10-22 19:15:09 +02:00
return $line ;
}
2021-02-23 22:03:23 +01:00
if ( $line != " " ) {
2016-06-25 14:38:10 +02:00
// group_concat support (PgSQL >= 9.0)
// Replace group_concat(x) or group_concat(x SEPARATOR ',') with string_agg(x, ',')
2020-10-31 14:32:18 +01:00
$line = preg_replace ( '/GROUP_CONCAT/i' , 'STRING_AGG' , $line );
2013-06-19 15:49:39 +02:00
$line = preg_replace ( '/ SEPARATOR/i' , ',' , $line );
2016-06-25 14:38:10 +02:00
$line = preg_replace ( '/STRING_AGG\(([^,\)]+)\)/i' , 'STRING_AGG(\\1, \',\')' , $line );
//print $line."\n";
2017-06-20 13:28:34 +02:00
2021-02-23 22:03:23 +01:00
if ( $type == 'auto' ) {
if ( preg_match ( '/ALTER TABLE/i' , $line )) {
$type = 'dml' ;
} elseif ( preg_match ( '/CREATE TABLE/i' , $line )) {
$type = 'dml' ;
} elseif ( preg_match ( '/DROP TABLE/i' , $line )) {
$type = 'dml' ;
}
2020-10-31 14:32:18 +01:00
}
$line = preg_replace ( '/ as signed\)/i' , ' as integer)' , $line );
2021-02-23 22:03:23 +01:00
if ( $type == 'dml' ) {
2020-10-31 14:32:18 +01:00
$reg = array ();
$line = preg_replace ( '/\s/' , ' ' , $line ); // Replace tabulation with space
// we are inside create table statement so lets process datatypes
if ( preg_match ( '/(ISAM|innodb)/i' , $line )) { // end of create table sequence
$line = preg_replace ( '/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i' , ');' , $line );
$line = preg_replace ( '/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb).*;/i' , ');' , $line );
$line = preg_replace ( '/,$/' , '' , $line );
}
// Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
if ( preg_match ( '/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i' , $line , $reg )) {
$newline = preg_replace ( '/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i' , '\\1 \\2 SERIAL PRIMARY KEY' , $line );
//$line = "-- ".$line." replaced by --\n".$newline;
$line = $newline ;
}
if ( preg_match ( '/[\s\t\(]*(\w*)[\s\t]+bigint.*auto_increment/i' , $line , $reg )) {
$newline = preg_replace ( '/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+bigint.*auto_increment[^,]*/i' , '\\1 \\2 BIGSERIAL PRIMARY KEY' , $line );
//$line = "-- ".$line." replaced by --\n".$newline;
$line = $newline ;
}
// tinyint type conversion
$line = preg_replace ( '/tinyint\(?[0-9]*\)?/' , 'smallint' , $line );
$line = preg_replace ( '/tinyint/i' , 'smallint' , $line );
// nuke unsigned
2021-06-22 18:59:14 +02:00
$line = preg_replace ( '/(int\w+|smallint|bigint)\s+unsigned/i' , '\\1' , $line );
2020-10-31 14:32:18 +01:00
// blob -> text
$line = preg_replace ( '/\w*blob/i' , 'text' , $line );
// tinytext/mediumtext -> text
$line = preg_replace ( '/tinytext/i' , 'text' , $line );
$line = preg_replace ( '/mediumtext/i' , 'text' , $line );
$line = preg_replace ( '/longtext/i' , 'text' , $line );
$line = preg_replace ( '/text\([0-9]+\)/i' , 'text' , $line );
// change not null datetime field to null valid ones
// (to support remapping of "zero time" to null
$line = preg_replace ( '/datetime not null/i' , 'datetime' , $line );
$line = preg_replace ( '/datetime/i' , 'timestamp' , $line );
// double -> numeric
$line = preg_replace ( '/^double/i' , 'numeric' , $line );
$line = preg_replace ( '/(\s*)double/i' , '\\1numeric' , $line );
// float -> numeric
$line = preg_replace ( '/^float/i' , 'numeric' , $line );
$line = preg_replace ( '/(\s*)float/i' , '\\1numeric' , $line );
//Check tms timestamp field case (in Mysql this field is defautled to now and
// on update defaulted by now
$line = preg_replace ( '/(\s*)tms(\s*)timestamp/i' , '\\1tms timestamp without time zone DEFAULT now() NOT NULL' , $line );
// nuke DEFAULT CURRENT_TIMESTAMP
$line = preg_replace ( '/(\s*)DEFAULT(\s*)CURRENT_TIMESTAMP/i' , '\\1' , $line );
// nuke ON UPDATE CURRENT_TIMESTAMP
$line = preg_replace ( '/(\s*)ON(\s*)UPDATE(\s*)CURRENT_TIMESTAMP/i' , '\\1' , $line );
// unique index(field1,field2)
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/unique index\s*\((\w+\s*,\s*\w+)\)/i' , $line )) {
2020-10-31 14:32:18 +01:00
$line = preg_replace ( '/unique index\s*\((\w+\s*,\s*\w+)\)/i' , 'UNIQUE\(\\1\)' , $line );
}
// We remove end of requests "AFTER fieldxxx"
$line = preg_replace ( '/\sAFTER [a-z0-9_]+/i' , '' , $line );
// We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
$line = preg_replace ( '/ALTER TABLE [a-z0-9_]+\s+DROP INDEX/i' , 'DROP INDEX' , $line );
// Translate order to rename fields
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER TABLE ([a-z0-9_]+)\s+CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = " -- " . $line . " replaced by -- \n " ;
$line .= " ALTER TABLE " . $reg [ 1 ] . " RENAME COLUMN " . $reg [ 2 ] . " TO " . $reg [ 3 ];
}
// Translate order to modify field format
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER TABLE ([a-z0-9_]+)\s+MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = " -- " . $line . " replaced by -- \n " ;
$newreg3 = $reg [ 3 ];
$newreg3 = preg_replace ( '/ DEFAULT NULL/i' , '' , $newreg3 );
$newreg3 = preg_replace ( '/ NOT NULL/i' , '' , $newreg3 );
$newreg3 = preg_replace ( '/ NULL/i' , '' , $newreg3 );
$newreg3 = preg_replace ( '/ DEFAULT 0/i' , '' , $newreg3 );
$newreg3 = preg_replace ( '/ DEFAULT \'?[0-9a-zA-Z_@]*\'?/i' , '' , $newreg3 );
$line .= " ALTER TABLE " . $reg [ 1 ] . " ALTER COLUMN " . $reg [ 2 ] . " TYPE " . $newreg3 ;
// TODO Add alter to set default value or null/not null if there is this in $reg[3]
}
// alter table add primary key (field1, field2 ...) -> We remove the primary key name not accepted by PostGreSQL
// ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity)
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = " -- " . $line . " replaced by -- \n " ;
$line .= " ALTER TABLE " . $reg [ 1 ] . " ADD PRIMARY KEY ( " . $reg [ 3 ];
}
// Translate order to drop primary keys
// ALTER TABLE llx_dolibarr_modules DROP PRIMARY KEY pk_xxx
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER\s+TABLE\s*(.*)\s*DROP\s+PRIMARY\s+KEY\s*([^;]+)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = " -- " . $line . " replaced by -- \n " ;
$line .= " ALTER TABLE " . $reg [ 1 ] . " DROP CONSTRAINT " . $reg [ 2 ];
}
// Translate order to drop foreign keys
// ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = " -- " . $line . " replaced by -- \n " ;
$line .= " ALTER TABLE " . $reg [ 1 ] . " DROP CONSTRAINT " . $reg [ 2 ];
}
// Translate order to add foreign keys
// ALTER TABLE llx_tablechild ADD CONSTRAINT fk_tablechild_fk_fieldparent FOREIGN KEY (fk_fieldparent) REFERENCES llx_tableparent (rowid)
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER\s+TABLE\s+(.*)\s*ADD CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*(.*)$/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$line = preg_replace ( '/;$/' , '' , $line );
$line .= " DEFERRABLE INITIALLY IMMEDIATE; " ;
}
// alter table add [unique] [index] (field1, field2 ...)
// ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i' , $line , $reg )) {
2020-10-31 14:32:18 +01:00
$fieldlist = $reg [ 4 ];
$idxname = $reg [ 3 ];
$tablename = $reg [ 1 ];
$line = " -- " . $line . " replaced by -- \n " ;
$line .= " CREATE " . ( preg_match ( '/UNIQUE/' , $reg [ 2 ]) ? 'UNIQUE ' : '' ) . " INDEX " . $idxname . " ON " . $tablename . " ( " . $fieldlist . " ) " ;
}
}
// To have postgresql case sensitive
2020-04-10 10:59:32 +02:00
$count_like = 0 ;
$line = str_replace ( ' LIKE \'' , ' ILIKE \'' , $line , $count_like );
2021-02-23 22:03:23 +01:00
if ( ! empty ( $conf -> global -> PSQL_USE_UNACCENT ) && $count_like > 0 ) {
2019-02-07 17:47:17 +01:00
// @see https://docs.postgresql.fr/11/unaccent.html : 'unaccent()' function must be installed before
2020-04-10 10:59:32 +02:00
$line = preg_replace ( '/\s+(\(+\s*)([a-zA-Z0-9\-\_\.]+) ILIKE /' , ' \1unaccent(\2) ILIKE ' , $line );
2019-02-07 17:47:17 +01:00
}
2020-10-31 14:32:18 +01:00
$line = str_replace ( ' LIKE BINARY \'' , ' LIKE \'' , $line );
2012-11-11 15:10:01 +01:00
2020-10-31 14:32:18 +01:00
// Replace INSERT IGNORE into INSERT
$line = preg_replace ( '/^INSERT IGNORE/' , 'INSERT' , $line );
2014-08-30 19:58:38 +02:00
2009-10-29 02:12:53 +01:00
// Delete using criteria on other table must not declare twice the deleted table
// DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i' , $line , $reg )) {
if ( $reg [ 1 ] == $reg [ 2 ]) { // If same table, we remove second one
2020-04-10 10:59:32 +02:00
$line = preg_replace ( '/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i' , 'DELETE FROM \\1 USING \\3' , $line );
2009-10-29 02:12:53 +01:00
}
}
2012-02-19 13:11:35 +01:00
// Remove () in the tables in FROM if 1 table
2020-04-10 10:59:32 +02:00
$line = preg_replace ( '/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i' , 'FROM \\1' , $line );
2010-05-09 16:08:42 +02:00
//print $line."\n";
2009-10-29 02:26:38 +01:00
2012-02-19 13:11:35 +01:00
// Remove () in the tables in FROM if 2 table
2020-04-10 10:59:32 +02:00
$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 );
2010-05-09 16:08:42 +02:00
//print $line."\n";
2009-10-29 02:12:53 +01:00
2012-02-19 13:11:35 +01:00
// Remove () in the tables in FROM if 3 table
2020-04-10 10:59:32 +02:00
$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 );
2010-05-09 16:08:42 +02:00
//print $line."\n";
2009-01-25 18:56:42 +01:00
2012-02-19 13:11:35 +01:00
// Remove () in the tables in FROM if 4 table
2020-04-10 10:59:32 +02:00
$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 );
2012-02-19 13:11:35 +01:00
//print $line."\n";
// Remove () in the tables in FROM if 5 table
2020-04-10 10:59:32 +02:00
$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 );
2012-02-19 13:11:35 +01:00
//print $line."\n";
2010-08-18 15:49:38 +02:00
// Replace espacing \' by ''.
2012-05-13 14:30:11 +02:00
// By default we do not (should be already done by db->escape function if required
// except for sql insert in data file that are mysql escaped so we removed them to
// be compatible with standard_conforming_strings=on that considers \ as ordinary character).
2021-02-23 22:03:23 +01:00
if ( $unescapeslashquot ) {
$line = preg_replace ( " / \\ \ '/ " , " '' " , $line );
}
2010-08-13 01:24:21 +02:00
2010-11-16 21:14:29 +01:00
//print "type=".$type." newline=".$line."<br>\n";
2010-05-09 16:08:42 +02:00
}
2009-01-25 18:56:42 +01:00
2008-09-06 01:38:14 +02:00
return $line ;
2008-09-06 01:08:07 +02:00
}
2009-01-25 18:56:42 +01:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Select a database
* Ici postgresql n ' a aucune fonction equivalente de mysql_select_db
* On compare juste manuellement si la database choisie est bien celle activee par la connexion
2011-09-03 01:09:39 +02:00
*
* @ param string $database Name of database
2015-05-12 18:31:12 +02:00
* @ return bool true if OK , false if KO
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function select_db ( $database )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
if ( $database == $this -> database_name ) {
return true ;
} else {
return false ;
}
}
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Connexion to server
*
2012-01-06 14:51:09 +01:00
* @ param string $host Database server host
* @ param string $login Login
* @ param string $passwd Password
* @ param string $name Name of database ( not used for mysql , used for pgsql )
2015-03-06 03:10:01 +01:00
* @ param integer $port Port of database server
2019-11-14 09:13:15 +01:00
* @ return bool | resource Database access handler
2019-03-23 12:36:05 +01:00
* @ see close ()
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function connect ( $host , $login , $passwd , $name , $port = 0 )
2009-10-22 19:15:09 +02:00
{
2012-01-06 14:51:09 +01:00
// use pg_pconnect() instead of pg_connect() if you want to use persistent connection costing 1ms, instead of 30ms for non persistent
2012-01-06 09:31:02 +01:00
$this -> db = false ;
2012-01-06 14:51:09 +01:00
2012-01-06 09:31:02 +01:00
// connections parameters must be protected (only \ and ' according to pg_connect() manual)
$host = str_replace ( array ( " \\ " , " ' " ), array ( " \\ \\ " , " \\ ' " ), $host );
$login = str_replace ( array ( " \\ " , " ' " ), array ( " \\ \\ " , " \\ ' " ), $login );
$passwd = str_replace ( array ( " \\ " , " ' " ), array ( " \\ \\ " , " \\ ' " ), $passwd );
$name = str_replace ( array ( " \\ " , " ' " ), array ( " \\ \\ " , " \\ ' " ), $name );
$port = str_replace ( array ( " \\ " , " ' " ), array ( " \\ \\ " , " \\ ' " ), $port );
2012-01-06 14:51:09 +01:00
2021-02-23 22:03:23 +01:00
if ( ! $name ) {
$name = " postgres " ; // When try to connect using admin user
}
2012-01-06 14:51:09 +01:00
2012-01-06 09:31:02 +01:00
// try first Unix domain socket (local)
2021-02-23 22:03:23 +01:00
if (( ! empty ( $host ) && $host == " socket " ) && ! defined ( 'NOLOCALSOCKETPGCONNECT' )) {
2020-04-10 10:59:32 +02:00
$con_string = " dbname=' " . $name . " ' user=' " . $login . " ' password=' " . $passwd . " ' " ; // $name may be empty
2014-12-26 00:12:16 +01:00
$this -> db = @ pg_connect ( $con_string );
2009-10-22 19:15:09 +02:00
}
2012-01-06 14:51:09 +01:00
2012-01-06 09:31:02 +01:00
// if local connection failed or not requested, use TCP/IP
2021-02-23 22:03:23 +01:00
if ( ! $this -> db ) {
if ( ! $host ) {
$host = " localhost " ;
}
if ( ! $port ) {
$port = 5432 ;
}
2012-01-06 14:51:09 +01:00
2012-01-06 09:31:02 +01:00
$con_string = " host=' " . $host . " ' port=' " . $port . " ' dbname=' " . $name . " ' user=' " . $login . " ' password=' " . $passwd . " ' " ;
2014-12-26 00:12:16 +01:00
$this -> db = @ pg_connect ( $con_string );
2010-04-16 11:12:07 +02:00
}
2012-01-06 14:51:09 +01:00
// now we test if at least one connect method was a success
2021-02-23 22:03:23 +01:00
if ( $this -> db ) {
2009-10-22 19:15:09 +02:00
$this -> database_name = $name ;
2020-04-10 10:59:32 +02:00
pg_set_error_verbosity ( $this -> db , PGSQL_ERRORS_VERBOSE ); // Set verbosity to max
2017-01-29 23:05:20 +01:00
pg_query ( $this -> db , " set datestyle = 'ISO, YMD'; " );
2009-10-22 19:15:09 +02:00
}
2012-01-06 14:51:09 +01:00
2009-10-22 19:15:09 +02:00
return $this -> db ;
}
/**
2011-09-03 01:09:39 +02:00
* Return version of database server
*
* @ return string Version string
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getVersion ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( 'SHOW server_version' );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$liste = $this -> fetch_array ( $resql );
return $liste [ 'server_version' ];
2010-08-01 23:42:57 +02:00
}
return '' ;
2009-10-22 19:15:09 +02:00
}
2013-06-12 11:59:55 +02:00
/**
* Return version of database client driver
*
* @ return string Version string
*/
2020-10-31 14:32:18 +01:00
public function getDriverInfo ()
2013-06-12 11:59:55 +02:00
{
2015-04-12 04:01:28 +02:00
return 'pgsql php driver' ;
2013-06-07 19:19:11 +02:00
}
2013-12-15 14:26:27 +01:00
2020-10-31 14:32:18 +01:00
/**
* Close database connexion
*
* @ return boolean True if disconnect successfull , false otherwise
* @ see connect ()
*/
public function close ()
{
2021-02-23 22:03:23 +01:00
if ( $this -> db ) {
if ( $this -> transaction_opened > 0 ) {
dol_syslog ( get_class ( $this ) . " ::close Closing a connection with an opened transaction depth= " . $this -> transaction_opened , LOG_ERR );
}
2020-10-31 14:32:18 +01:00
$this -> connected = false ;
return pg_close ( $this -> db );
}
return false ;
}
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Convert request to PostgreSQL syntax , execute it and return the resultset
*
2012-01-04 14:35:41 +01:00
* @ param string $query SQL query string
* @ param int $usesavepoint 0 = Default mode , 1 = Run a savepoint before and a rollback to savepoint if error ( this allow to have some request with errors inside global transactions ) .
2020-10-31 14:32:18 +01:00
* @ param string $type Type of SQL order ( 'ddl' for insert , update , select , delete or 'dml' for create , alter ... )
2015-05-12 18:31:12 +02:00
* @ return false | resource Resultset of answer
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function query ( $query , $usesavepoint = 0 , $type = 'auto' )
2009-10-22 19:15:09 +02:00
{
2014-03-15 23:12:00 +01:00
global $conf ;
2014-05-29 19:30:51 +02:00
2009-10-22 19:15:09 +02:00
$query = trim ( $query );
2009-01-25 18:56:42 +01:00
2009-10-22 20:21:06 +02:00
// Convert MySQL syntax to PostgresSQL syntax
2020-04-10 10:59:32 +02:00
$query = $this -> convertSQLFromMysql ( $query , $type , ( $this -> unescapeslashquot && $this -> standard_conforming_strings ));
2012-01-02 02:46:12 +01:00
//print "After convertSQLFromMysql:\n".$query."<br>\n";
2009-10-28 18:37:40 +01:00
2021-02-23 22:03:23 +01:00
if ( ! empty ( $conf -> global -> MAIN_DB_AUTOFIX_BAD_SQL_REQUEST )) {
2014-03-15 23:12:00 +01:00
// Fix bad formed requests. If request contains a date without quotes, we fix this but this should not occurs.
2020-04-10 10:59:32 +02:00
$loop = true ;
2021-02-23 22:03:23 +01:00
while ( $loop ) {
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 )) {
2020-04-10 10:59:32 +02:00
$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 );
2019-01-27 11:55:16 +01:00
dol_syslog ( " Warning: Bad formed request converted into " . $query , LOG_WARNING );
2021-02-23 22:03:23 +01:00
} else {
$loop = false ;
}
2009-10-28 18:37:40 +01:00
}
}
2014-05-29 19:30:51 +02:00
2021-02-23 22:03:23 +01:00
if ( $usesavepoint && $this -> transaction_opened ) {
2010-04-30 19:31:46 +02:00
@ pg_query ( $this -> db , 'SAVEPOINT mysavepoint' );
}
2021-02-23 22:03:23 +01:00
if ( ! in_array ( $query , array ( 'BEGIN' , 'COMMIT' , 'ROLLBACK' ))) {
2020-04-10 10:59:32 +02:00
$SYSLOG_SQL_LIMIT = 10000 ; // limit log to 10kb per line to limit DOS attacks
2019-08-29 03:54:31 +02:00
dol_syslog ( 'sql=' . substr ( $query , 0 , $SYSLOG_SQL_LIMIT ), LOG_DEBUG );
}
2014-06-09 15:38:43 +02:00
2014-07-27 23:23:29 +02:00
$ret = @ pg_query ( $this -> db , $query );
2010-04-16 11:50:33 +02:00
//print $query;
2021-02-23 22:03:23 +01:00
if ( ! preg_match ( " /^COMMIT/i " , $query ) && ! preg_match ( " /^ROLLBACK/i " , $query )) { // Si requete utilisateur, on la sauvegarde ainsi que son resultset
if ( ! $ret ) {
if ( $this -> errno () != 'DB_ERROR_25P02' ) { // Do not overwrite errors if this is a consecutive error
2020-10-31 14:32:18 +01:00
$this -> lastqueryerror = $query ;
$this -> lasterror = $this -> error ();
$this -> lasterrno = $this -> errno ();
2014-06-13 01:52:57 +02:00
2021-02-23 22:03:23 +01:00
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
}
2015-07-22 23:33:48 +02:00
dol_syslog ( get_class ( $this ) . " ::query SQL Error message: " . $this -> lasterror . " ( " . $this -> lasterrno . " ) " , LOG_ERR );
dol_syslog ( get_class ( $this ) . " ::query SQL Error usesavepoint = " . $usesavepoint , LOG_ERR );
2020-10-31 14:32:18 +01:00
}
2010-04-30 19:31:46 +02:00
2021-02-23 22:03:23 +01:00
if ( $usesavepoint && $this -> transaction_opened ) { // Warning, after that errno will be erased
2010-04-30 19:31:46 +02:00
@ pg_query ( $this -> db , 'ROLLBACK TO SAVEPOINT mysavepoint' );
}
2009-10-22 19:15:09 +02:00
}
2020-04-10 10:59:32 +02:00
$this -> lastquery = $query ;
2012-02-15 13:55:00 +01:00
$this -> _results = $ret ;
2009-10-22 19:15:09 +02:00
}
return $ret ;
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Renvoie la ligne courante ( comme un objet ) pour le curseur resultset
*
2015-05-12 18:31:12 +02:00
* @ param resource $resultset Curseur de la requete voulue
* @ return false | object Object result line or false if KO or end of cursor
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function fetch_object ( $resultset )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
// If resultset not provided, we take the last used by connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2009-10-22 19:15:09 +02:00
return pg_fetch_object ( $resultset );
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return datas as an array
*
* @ param resource $resultset Resultset of request
* @ return false | array Array
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function fetch_array ( $resultset )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
// If resultset not provided, we take the last used by connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2009-10-22 19:15:09 +02:00
return pg_fetch_array ( $resultset );
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2020-10-31 14:32:18 +01:00
* Return datas as an array
*
* @ param resource $resultset Resultset of request
* @ return false | array Array
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function fetch_row ( $resultset )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2009-10-22 19:15:09 +02:00
// Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2009-10-22 19:15:09 +02:00
return pg_fetch_row ( $resultset );
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
/**
* Return number of lines for result of a SELECT
*
* @ param resource $resultset Resulset of requests
* @ return int Nb of lines , - 1 on error
* @ see affected_rows ()
*/
public function num_rows ( $resultset )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
// If resultset not provided, we take the last used by connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2009-10-22 19:15:09 +02:00
return pg_num_rows ( $resultset );
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2019-06-29 16:29:32 +02:00
* Return the number of lines in the result of a request INSERT , DELETE or UPDATE
2011-09-03 01:09:39 +02:00
*
2015-05-12 18:31:12 +02:00
* @ param resource $resultset Result set of request
2012-01-06 14:51:09 +01:00
* @ return int Nb of lines
2019-06-29 16:29:32 +02:00
* @ see num_rows ()
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function affected_rows ( $resultset )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
// If resultset not provided, we take the last used by connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2009-10-22 19:15:09 +02:00
// pgsql necessite un resultset pour cette fonction contrairement
// a mysql qui prend un link de base
return pg_affected_rows ( $resultset );
}
/**
2011-09-03 01:09:39 +02:00
* Libere le dernier resultset utilise sur cette connexion
*
2015-05-12 18:31:12 +02:00
* @ param resource $resultset Result set of request
2012-01-04 14:35:41 +01:00
* @ return void
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function free ( $resultset = null )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// If resultset not provided, we take the last used by connexion
2021-02-23 22:03:23 +01:00
if ( ! is_resource ( $resultset )) {
$resultset = $this -> _results ;
}
2010-11-15 20:08:35 +01:00
// Si resultset en est un, on libere la memoire
2021-02-23 22:03:23 +01:00
if ( is_resource ( $resultset )) {
pg_free_result ( $resultset );
}
2009-10-22 19:15:09 +02:00
}
/**
2020-10-31 14:32:18 +01:00
* Define limits and offset of request
*
* @ param int $limit Maximum number of lines returned ( - 1 = conf -> liste_limit , 0 = no limit )
* @ param int $offset Numero of line from where starting fetch
* @ return string String with SQL syntax to add a limit and offset
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function plimit ( $limit = 0 , $offset = 0 )
2009-10-22 19:15:09 +02:00
{
global $conf ;
2021-02-23 22:03:23 +01:00
if ( empty ( $limit )) {
return " " ;
}
if ( $limit < 0 ) {
$limit = $conf -> liste_limit ;
}
if ( $offset > 0 ) {
return " LIMIT " . $limit . " OFFSET " . $offset . " " ;
} else {
return " LIMIT $limit " ;
}
2009-10-22 19:15:09 +02:00
}
2006-06-24 22:58:22 +02:00
2008-04-21 15:17:36 +02:00
/**
2011-09-03 01:09:39 +02:00
* Escape a string to insert data
*
2012-01-04 14:35:41 +01:00
* @ param string $stringtoencode String to escape
* @ return string String escaped
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function escape ( $stringtoencode )
2008-04-21 15:17:36 +02:00
{
2010-08-13 00:23:44 +02:00
return pg_escape_string ( $stringtoencode );
2008-04-21 15:17:36 +02:00
}
2021-09-26 14:21:23 +02:00
/**
* Escape a string to insert data
*
* @ param string $stringtoencode String to escape
* @ return string String escaped
*/
public function escapeunderscore ( $stringtoencode )
{
return str_replace ( '_' , '\_' , $stringtoencode );
}
2009-10-22 19:15:09 +02:00
/**
2020-10-31 14:32:18 +01:00
* Format a SQL IF
*
2012-02-24 11:23:52 +01:00
* @ param string $test Test string ( example : 'cd.statut=0' , 'field IS NULL' )
2012-01-04 14:35:41 +01:00
* @ param string $resok resultat si test egal
* @ param string $resko resultat si test non egal
* @ return string chaine formate SQL
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function ifsql ( $test , $resok , $resko )
2009-10-22 19:15:09 +02:00
{
2010-05-12 19:46:39 +02:00
return '(CASE WHEN ' . $test . ' THEN ' . $resok . ' ELSE ' . $resko . ' END)' ;
2009-10-22 19:15:09 +02:00
}
/**
2011-09-03 01:09:39 +02:00
* Renvoie le code erreur generique de l ' operation precedente .
*
2014-12-20 15:42:03 +01:00
* @ return string Error code ( Exemples : DB_ERROR_TABLE_ALREADY_EXISTS , DB_ERROR_RECORD_ALREADY_EXISTS ... )
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function errno ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
if ( ! $this -> connected ) {
2009-10-22 20:21:06 +02:00
// Si il y a eu echec de connexion, $this->db n'est pas valide.
return 'DB_ERROR_FAILED_TO_CONNECT' ;
2020-05-21 15:05:19 +02:00
} else {
2012-01-02 02:46:12 +01:00
// Constants to convert error code to a generic Dolibarr error code
2009-10-22 20:21:06 +02:00
$errorcode_map = array (
1004 => 'DB_ERROR_CANNOT_CREATE' ,
1005 => 'DB_ERROR_CANNOT_CREATE' ,
1006 => 'DB_ERROR_CANNOT_CREATE' ,
1007 => 'DB_ERROR_ALREADY_EXISTS' ,
1008 => 'DB_ERROR_CANNOT_DROP' ,
1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP' ,
1044 => 'DB_ERROR_ACCESSDENIED' ,
1046 => 'DB_ERROR_NODBSELECTED' ,
1048 => 'DB_ERROR_CONSTRAINT' ,
2009-10-25 18:57:23 +01:00
'42P07' => 'DB_ERROR_TABLE_OR_KEY_ALREADY_EXISTS' ,
2009-10-25 19:53:09 +01:00
'42703' => 'DB_ERROR_NOSUCHFIELD' ,
2009-10-22 20:21:06 +02:00
1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS' ,
2010-04-30 20:30:23 +02:00
42701 => 'DB_ERROR_COLUMN_ALREADY_EXISTS' ,
2009-10-25 17:30:26 +01:00
'42710' => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS' ,
2009-10-25 19:53:09 +01:00
'23505' => 'DB_ERROR_RECORD_ALREADY_EXISTS' ,
2020-04-10 10:59:32 +02:00
'42704' => 'DB_ERROR_NO_INDEX_TO_DROP' , // May also be Type xxx does not exists
2009-10-24 01:01:03 +02:00
'42601' => 'DB_ERROR_SYNTAX' ,
2009-10-25 18:57:23 +01:00
'42P16' => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS' ,
2009-10-22 20:21:06 +02:00
1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY' ,
1091 => 'DB_ERROR_NOSUCHFIELD' ,
1100 => 'DB_ERROR_NOT_LOCKED' ,
1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW' ,
2009-10-25 19:53:09 +01:00
'42P01' => 'DB_ERROR_NOSUCHTABLE' ,
'23503' => 'DB_ERROR_NO_PARENT' ,
2009-10-22 20:21:06 +02:00
1217 => 'DB_ERROR_CHILD_EXISTS' ,
2010-11-16 20:12:25 +01:00
1451 => 'DB_ERROR_CHILD_EXISTS' ,
'42P04' => 'DB_DATABASE_ALREADY_EXISTS'
2009-10-22 20:21:06 +02:00
);
2020-04-10 10:59:32 +02:00
$errorlabel = pg_last_error ( $this -> db );
$errorcode = '' ;
2021-06-22 17:09:02 +02:00
$reg = array ();
2021-02-23 22:03:23 +01:00
if ( preg_match ( '/: *([0-9P]+):/' , $errorlabel , $reg )) {
2020-04-10 10:59:32 +02:00
$errorcode = $reg [ 1 ];
2021-02-23 22:03:23 +01:00
if ( isset ( $errorcode_map [ $errorcode ])) {
2009-10-24 01:01:03 +02:00
return $errorcode_map [ $errorcode ];
}
2009-10-22 20:21:06 +02:00
}
2020-04-10 10:59:32 +02:00
$errno = $errorcode ? $errorcode : $errorlabel ;
return ( $errno ? 'DB_ERROR_' . $errno : '0' );
2009-10-22 20:21:06 +02:00
}
2009-10-25 19:53:09 +01:00
// '/(Table does not exist\.|Relation [\"\'].*[\"\'] does not exist|sequence does not exist|class ".+" not found)$/' => 'DB_ERROR_NOSUCHTABLE',
// '/table [\"\'].*[\"\'] does not exist/' => 'DB_ERROR_NOSUCHTABLE',
// '/Relation [\"\'].*[\"\'] already exists|Cannot insert a duplicate key into (a )?unique index.*/' => 'DB_ERROR_RECORD_ALREADY_EXISTS',
// '/divide by zero$/' => 'DB_ERROR_DIVZERO',
// '/pg_atoi: error in .*: can\'t parse /' => 'DB_ERROR_INVALID_NUMBER',
// '/ttribute [\"\'].*[\"\'] not found$|Relation [\"\'].*[\"\'] does not have attribute [\"\'].*[\"\']/' => 'DB_ERROR_NOSUCHFIELD',
// '/parser: parse error at or near \"/' => 'DB_ERROR_SYNTAX',
// '/referential integrity violation/' => 'DB_ERROR_CONSTRAINT'
2009-10-22 19:15:09 +02:00
}
/**
2011-09-03 01:09:39 +02:00
* Renvoie le texte de l 'erreur pgsql de l' operation precedente
*
2014-12-20 15:42:03 +01:00
* @ return string Error text
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function error ()
2009-10-22 19:15:09 +02:00
{
return pg_last_error ( $this -> db );
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Get last ID after an insert INSERT
*
2011-12-19 23:32:24 +01:00
* @ param string $tab Table name concerned by insert . Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql
* @ param string $fieldid Field name
2015-05-12 18:31:12 +02:00
* @ return string Id of row
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function last_insert_id ( $tab , $fieldid = 'rowid' )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2010-05-07 23:02:48 +02:00
//$result = pg_query($this->db,"SELECT MAX(".$fieldid.") FROM ".$tab);
2019-01-27 11:55:16 +01:00
$result = pg_query ( $this -> db , " SELECT currval(' " . $tab . " _ " . $fieldid . " _seq') " );
2021-02-23 22:03:23 +01:00
if ( ! $result ) {
2010-05-07 23:02:48 +02:00
print pg_last_error ( $this -> db );
exit ;
}
//$nbre = pg_num_rows($result);
2019-01-27 11:55:16 +01:00
$row = pg_fetch_result ( $result , 0 , 0 );
2009-10-22 19:15:09 +02:00
return $row ;
}
2006-11-15 02:04:38 +01:00
2009-07-03 10:22:06 +02:00
/**
2020-10-31 14:32:18 +01:00
* Encrypt sensitive data in database
* Warning : This function includes the escape , so it must use direct value
*
* @ param string $fieldorvalue Field name or value to encrypt
* @ param int $withQuotes Return string with quotes
* @ return string XXX ( field ) or XXX ( 'value' ) or field or 'value'
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function encrypt ( $fieldorvalue , $withQuotes = 0 )
2009-07-03 10:22:06 +02:00
{
2009-12-23 02:12:47 +01:00
global $conf ;
2010-02-03 03:22:15 +01:00
2009-12-23 02:12:47 +01:00
// Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
2020-04-10 10:59:32 +02:00
$cryptType = ( $conf -> db -> dolibarr_main_db_encryption ? $conf -> db -> dolibarr_main_db_encryption : 0 );
2010-02-03 03:22:15 +01:00
2009-12-23 02:12:47 +01:00
//Encryption key
2020-04-10 10:59:32 +02:00
$cryptKey = ( ! empty ( $conf -> db -> dolibarr_main_db_cryptkey ) ? $conf -> db -> dolibarr_main_db_cryptkey : '' );
2010-02-03 03:22:15 +01:00
2009-09-07 16:03:19 +02:00
$return = $fieldorvalue ;
2020-04-10 10:59:32 +02:00
return ( $withQuotes ? " ' " : " " ) . $this -> escape ( $return ) . ( $withQuotes ? " ' " : " " );
2009-07-03 10:22:06 +02:00
}
2009-09-07 16:03:19 +02:00
2009-07-03 10:22:06 +02:00
/**
2011-09-03 01:09:39 +02:00
* Decrypt sensitive data in database
*
2012-01-06 14:51:09 +01:00
* @ param int $value Value to decrypt
* @ return string Decrypted value if used
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function decrypt ( $value )
2009-07-03 10:22:06 +02:00
{
2009-12-23 02:12:47 +01:00
global $conf ;
2010-02-03 03:22:15 +01:00
2009-12-23 02:12:47 +01:00
// Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
2020-04-10 10:59:32 +02:00
$cryptType = ( $conf -> db -> dolibarr_main_db_encryption ? $conf -> db -> dolibarr_main_db_encryption : 0 );
2010-02-03 03:22:15 +01:00
2009-12-23 02:12:47 +01:00
//Encryption key
2020-04-10 10:59:32 +02:00
$cryptKey = ( ! empty ( $conf -> db -> dolibarr_main_db_cryptkey ) ? $conf -> db -> dolibarr_main_db_cryptkey : '' );
2010-02-03 03:22:15 +01:00
2009-12-23 02:12:47 +01:00
$return = $value ;
2009-07-03 10:22:06 +02:00
return $return ;
}
2006-11-15 02:04:38 +01:00
2009-09-07 16:03:19 +02:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-09-07 16:03:19 +02:00
/**
2012-01-28 17:22:02 +01:00
* Return connexion ID
2011-09-03 01:09:39 +02:00
*
* @ return string Id connexion
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLGetConnectId ()
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2009-10-22 19:15:09 +02:00
return '?' ;
}
2006-11-15 02:04:38 +01:00
2009-01-27 00:52:37 +01:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2011-09-03 01:09:39 +02:00
* Create a new database
2012-01-28 17:22:02 +01:00
* Do not use function xxx_create_db ( xxx = mysql , ... ) as they are deprecated
* We force to create database with charset this -> forcecharset and collate this -> forcecollate
2011-09-03 01:09:39 +02:00
*
2012-01-06 14:51:09 +01:00
* @ param string $database Database name to create
* @ param string $charset Charset used to store data
* @ param string $collation Charset used to sort data
* @ param string $owner Username of database owner
2015-05-12 18:31:12 +02:00
* @ return false | resource resource defined if OK , null if KO
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLCreateDb ( $database , $charset = '' , $collation = '' , $owner = '' )
2009-10-22 19:15:09 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2021-02-23 22:03:23 +01:00
if ( empty ( $charset )) {
$charset = $this -> forcecharset ;
}
if ( empty ( $collation )) {
$collation = $this -> forcecollate ;
}
2009-01-25 18:56:42 +01:00
2012-05-06 15:36:53 +02:00
// Test charset match LC_TYPE (pgsql error otherwise)
//print $charset.' '.setlocale(LC_CTYPE,'0'); exit;
2020-04-10 10:59:32 +02:00
$sql = 'CREATE DATABASE "' . $database . '" OWNER "' . $owner . '" ENCODING \'' . $charset . '\'' ;
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2020-04-10 10:59:32 +02:00
$ret = $this -> query ( $sql );
2009-10-22 19:15:09 +02:00
return $ret ;
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-10-22 19:15:09 +02:00
/**
2012-01-06 14:51:09 +01:00
* List tables into a database
*
* @ param string $database Name of database
2014-10-05 01:22:17 +02:00
* @ param string $table Name of table filter ( 'xxx%' )
* @ return array List of tables in an array
2009-10-22 19:15:09 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLListTables ( $database , $table = '' )
{
// phpcs:enable
2020-04-10 10:59:32 +02:00
$listtables = array ();
2010-04-30 19:31:46 +02:00
$like = '' ;
2021-02-23 22:03:23 +01:00
if ( $table ) {
$like = " AND table_name LIKE ' " . $this -> escape ( $table ) . " ' " ;
}
2010-11-16 21:14:29 +01:00
$result = pg_query ( $this -> db , " SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' " . $like . " ORDER BY table_name " );
2021-02-23 22:03:23 +01:00
if ( $result ) {
while ( $row = $this -> fetch_row ( $result )) {
2020-10-31 14:32:18 +01:00
$listtables [] = $row [ 0 ];
}
}
2014-10-05 01:22:17 +02:00
return $listtables ;
2009-10-22 19:15:09 +02:00
}
2009-07-30 00:59:18 +02:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-07-03 10:22:06 +02:00
/**
2012-01-06 14:51:09 +01:00
* List information of columns into a table .
*
* @ param string $table Name of table
* @ return array Tableau des informations des champs de la table
2012-10-24 11:37:00 +02:00
*
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLInfoTable ( $table )
2009-07-03 10:22:06 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2020-04-10 10:59:32 +02:00
$infotables = array ();
$sql = " SELECT " ;
$sql .= " infcol.column_name as \" Column \" , " ;
$sql .= " CASE WHEN infcol.character_maximum_length IS NOT NULL THEN infcol.udt_name || '('||infcol.character_maximum_length||')' " ;
$sql .= " ELSE infcol.udt_name " ;
$sql .= " END as \" Type \" , " ;
$sql .= " infcol.collation_name as \" Collation \" , " ;
$sql .= " infcol.is_nullable as \" Null \" , " ;
$sql .= " '' as \" Key \" , " ;
$sql .= " infcol.column_default as \" Default \" , " ;
$sql .= " '' as \" Extra \" , " ;
$sql .= " '' as \" Privileges \" " ;
$sql .= " FROM information_schema.columns infcol " ;
$sql .= " WHERE table_schema='public' " ;
2020-09-19 21:19:04 +02:00
$sql .= " AND table_name=' " . $this -> escape ( $table ) . " ' " ;
2020-04-10 10:59:32 +02:00
$sql .= " ORDER BY ordinal_position; " ;
2016-05-17 23:14:30 +02:00
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2016-05-17 23:14:30 +02:00
$result = $this -> query ( $sql );
2021-02-23 22:03:23 +01:00
if ( $result ) {
while ( $row = $this -> fetch_row ( $result )) {
2020-10-31 14:32:18 +01:00
$infotables [] = $row ;
}
2016-05-17 23:14:30 +02:00
}
2020-10-31 14:32:18 +01:00
return $infotables ;
2009-07-03 10:22:06 +02:00
}
2005-09-04 03:48:09 +02:00
2009-01-25 18:56:42 +01:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2010-05-07 23:02:48 +02:00
/**
2011-09-12 19:08:02 +02:00
* Create a table into database
2011-09-03 01:09:39 +02:00
*
2011-09-12 19:08:02 +02:00
* @ param string $table Nom de la table
* @ param array $fields Tableau associatif [ nom champ ][ tableau des descriptions ]
* @ param string $primary_key Nom du champ qui sera la clef primaire
* @ param string $type Type de la table
* @ param array $unique_keys Tableau associatifs Nom de champs qui seront clef unique => valeur
* @ param array $fulltext_keys Tableau des Nom de champs qui seront indexes en fulltext
2015-05-12 18:31:12 +02:00
* @ param array $keys Tableau des champs cles noms => valeur
2011-09-12 19:08:02 +02:00
* @ return int < 0 if KO , >= 0 if OK
2010-05-07 23:02:48 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLCreateTable ( $table , $fields , $primary_key , $type , $unique_keys = null , $fulltext_keys = null , $keys = null )
2010-05-07 23:02:48 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2015-05-12 18:31:12 +02:00
// FIXME: $fulltext_keys parameter is unused
2010-05-07 23:02:48 +02:00
// cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
// ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
$sql = " create table " . $table . " ( " ;
2020-04-10 10:59:32 +02:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
foreach ( $fields as $field_name => $field_desc ) {
2010-05-07 23:02:48 +02:00
$sqlfields [ $i ] = $field_name . " " ;
2020-04-10 10:59:32 +02:00
$sqlfields [ $i ] .= $field_desc [ 'type' ];
2021-02-23 22:03:23 +01:00
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'value' ])) {
2020-10-31 14:32:18 +01:00
$sqlfields [ $i ] .= " ( " . $field_desc [ 'value' ] . " ) " ;
2021-02-23 22:03:23 +01:00
} elseif ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'attribute' ])) {
2020-10-31 14:32:18 +01:00
$sqlfields [ $i ] .= " " . $field_desc [ 'attribute' ];
2021-02-23 22:03:23 +01:00
} elseif ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'default' ])) {
if ( preg_match ( " /null/i " , $field_desc [ 'default' ])) {
2020-10-31 14:32:18 +01:00
$sqlfields [ $i ] .= " default " . $field_desc [ 'default' ];
2021-02-23 22:03:23 +01:00
} else {
$sqlfields [ $i ] .= " default ' " . $this -> escape ( $field_desc [ 'default' ]) . " ' " ;
}
} elseif ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'null' ])) {
2020-10-31 14:32:18 +01:00
$sqlfields [ $i ] .= " " . $field_desc [ 'null' ];
2021-02-23 22:03:23 +01:00
} elseif ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'extra' ])) {
2020-10-31 14:32:18 +01:00
$sqlfields [ $i ] .= " " . $field_desc [ 'extra' ];
2021-02-23 22:03:23 +01:00
}
2010-05-07 23:02:48 +02:00
$i ++ ;
}
2021-02-23 22:03:23 +01:00
if ( $primary_key != " " ) {
$pk = " primary key( " . $primary_key . " ) " ;
}
2010-05-07 23:02:48 +02:00
2021-02-23 22:03:23 +01:00
if ( is_array ( $unique_keys )) {
2010-05-07 23:02:48 +02:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
foreach ( $unique_keys as $key => $value ) {
2020-09-19 21:19:04 +02:00
$sqluq [ $i ] = " UNIQUE KEY ' " . $key . " ' (' " . $this -> escape ( $value ) . " ') " ;
2010-05-07 23:02:48 +02:00
$i ++ ;
}
}
2021-02-23 22:03:23 +01:00
if ( is_array ( $keys )) {
2010-05-07 23:02:48 +02:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
foreach ( $keys as $key => $value ) {
2010-05-07 23:02:48 +02:00
$sqlk [ $i ] = " KEY " . $key . " ( " . $value . " ) " ;
$i ++ ;
}
}
2019-01-27 11:55:16 +01:00
$sql .= implode ( ',' , $sqlfields );
2021-02-23 22:03:23 +01:00
if ( $primary_key != " " ) {
$sql .= " , " . $pk ;
}
if ( is_array ( $unique_keys )) {
$sql .= " , " . implode ( ',' , $sqluq );
}
if ( is_array ( $keys )) {
$sql .= " , " . implode ( ',' , $sqlk );
}
2020-04-10 10:59:32 +02:00
$sql .= " ) type= " . $type ;
2010-05-07 23:02:48 +02:00
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2021-02-23 22:03:23 +01:00
if ( ! $this -> query ( $sql )) {
return - 1 ;
} else {
return 1 ;
}
2010-05-07 23:02:48 +02:00
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2017-11-21 11:50:57 +01:00
/**
* Drop a table into database
*
* @ param string $table Name of table
* @ return int < 0 if KO , >= 0 if OK
*/
2020-10-31 14:32:18 +01:00
public function DDLDropTable ( $table )
2017-11-21 11:50:57 +01:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2017-11-21 11:50:57 +01:00
$sql = " DROP TABLE " . $table ;
2021-02-23 22:03:23 +01:00
if ( ! $this -> query ( $sql )) {
2017-11-21 11:50:57 +01:00
return - 1 ;
2021-02-23 22:03:23 +01:00
} else {
return 1 ;
}
2017-11-21 11:50:57 +01:00
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2007-05-08 23:54:11 +02:00
/**
2012-01-06 14:51:09 +01:00
* Create a user to connect to database
2011-09-03 01:09:39 +02:00
*
2014-02-25 18:25:17 +01:00
* @ param string $dolibarr_main_db_host Ip server
* @ param string $dolibarr_main_db_user Name of user to create
* @ param string $dolibarr_main_db_pass Password of user to create
2012-01-06 14:51:09 +01:00
* @ param string $dolibarr_main_db_name Database name where user must be granted
* @ return int < 0 if KO , >= 0 if OK
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLCreateUser ( $dolibarr_main_db_host , $dolibarr_main_db_user , $dolibarr_main_db_pass , $dolibarr_main_db_name )
2007-05-08 23:54:11 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2014-08-17 17:13:00 +02:00
// Note: using ' on user does not works with pgsql
$sql = " CREATE USER " . $this -> escape ( $dolibarr_main_db_user ) . " with password ' " . $this -> escape ( $dolibarr_main_db_pass ) . " ' " ;
2007-05-08 23:54:11 +02:00
2020-04-10 10:59:32 +02:00
dol_syslog ( get_class ( $this ) . " ::DDLCreateUser " , LOG_DEBUG ); // No sql to avoid password in log
$resql = $this -> query ( $sql );
2021-02-23 22:03:23 +01:00
if ( ! $resql ) {
2007-05-08 23:54:11 +02:00
return - 1 ;
}
2009-01-25 18:56:42 +01:00
2007-05-08 23:54:11 +02:00
return 1 ;
}
2009-01-25 18:56:42 +01:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2010-05-07 23:02:48 +02:00
/**
2012-01-06 14:51:09 +01:00
* Return a pointer of line with description of a table or field
2011-09-03 01:09:39 +02:00
*
2012-01-06 14:51:09 +01:00
* @ param string $table Name of table
* @ param string $field Optionnel : Name of field if we want description of field
2015-05-12 18:31:12 +02:00
* @ return false | resource Resultset x ( x -> attname )
2010-05-07 23:02:48 +02:00
*/
2020-10-31 14:32:18 +01:00
public function DDLDescTable ( $table , $field = " " )
2010-05-07 23:02:48 +02:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2020-09-19 21:19:04 +02:00
$sql = " SELECT attname FROM pg_attribute, pg_type WHERE typname = ' " . $this -> escape ( $table ) . " ' AND attrelid = typrelid " ;
2020-04-10 10:59:32 +02:00
$sql .= " AND attname NOT IN ('cmin', 'cmax', 'ctid', 'oid', 'tableoid', 'xmin', 'xmax') " ;
2021-02-23 22:03:23 +01:00
if ( $field ) {
$sql .= " AND attname = ' " . $this -> escape ( $field ) . " ' " ;
}
2010-05-07 23:02:48 +02:00
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2012-02-15 13:55:00 +01:00
$this -> _results = $this -> query ( $sql );
return $this -> _results ;
2010-05-07 23:02:48 +02:00
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-01-27 00:52:37 +01:00
/**
2012-01-06 14:51:09 +01:00
* Create a new field into table
2011-09-03 01:09:39 +02:00
*
2012-01-06 14:51:09 +01:00
* @ param string $table Name of table
* @ param string $field_name Name of field to add
* @ param string $field_desc Tableau associatif de description du champ a inserer [ nom du parametre ][ valeur du parametre ]
* @ param string $field_position Optionnel ex .: " after champtruc "
* @ return int < 0 if KO , > 0 if OK
2009-01-27 00:52:37 +01:00
*/
2020-10-31 14:32:18 +01:00
public function DDLAddField ( $table , $field_name , $field_desc , $field_position = " " )
2009-01-27 00:52:37 +01:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2009-07-03 10:22:06 +02:00
// cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
2009-01-27 00:52:37 +01:00
// ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
2020-04-10 10:59:32 +02:00
$sql = " ALTER TABLE " . $table . " ADD " . $field_name . " " ;
2009-01-27 00:52:37 +01:00
$sql .= $field_desc [ 'type' ];
2020-06-29 13:48:00 +02:00
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'value' ])) {
2021-02-23 22:03:23 +01:00
if ( ! in_array ( $field_desc [ 'type' ], array ( 'int' , 'date' , 'datetime' )) && $field_desc [ 'value' ]) {
2020-10-31 14:32:18 +01:00
$sql .= " ( " . $field_desc [ 'value' ] . " ) " ;
}
2020-06-29 13:48:00 +02:00
}
2021-02-23 22:03:23 +01:00
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'attribute' ])) {
2020-10-31 14:32:18 +01:00
$sql .= " " . $field_desc [ 'attribute' ];
2021-02-23 22:03:23 +01:00
}
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'null' ])) {
2020-10-31 14:32:18 +01:00
$sql .= " " . $field_desc [ 'null' ];
2021-02-23 22:03:23 +01:00
}
2019-10-27 17:01:23 +01:00
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'default' ])) {
2020-10-31 14:32:18 +01:00
if ( preg_match ( " /null/i " , $field_desc [ 'default' ])) {
$sql .= " default " . $field_desc [ 'default' ];
2019-10-27 17:01:23 +01:00
} else {
2020-09-19 21:19:04 +02:00
$sql .= " default ' " . $this -> escape ( $field_desc [ 'default' ]) . " ' " ;
2019-10-27 17:01:23 +01:00
}
}
if ( preg_match ( " /^[^ \ s]/i " , $field_desc [ 'extra' ])) {
$sql .= " " . $field_desc [ 'extra' ];
}
2009-01-27 00:52:37 +01:00
$sql .= " " . $field_position ;
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2021-02-23 22:03:23 +01:00
if ( ! $this -> query ( $sql )) {
2015-05-12 18:31:12 +02:00
return - 1 ;
2021-02-23 22:03:23 +01:00
}
2009-01-27 00:52:37 +01:00
return 1 ;
}
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2011-03-08 11:33:43 +01:00
/**
* Update format of a field into a table
2011-09-03 01:09:39 +02:00
*
2012-01-06 14:51:09 +01:00
* @ param string $table Name of table
* @ param string $field_name Name of field to modify
* @ param string $field_desc Array with description of field format
* @ return int < 0 if KO , > 0 if OK
2011-03-08 11:33:43 +01:00
*/
2020-10-31 14:32:18 +01:00
public function DDLUpdateField ( $table , $field_name , $field_desc )
2011-03-08 11:33:43 +01:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2011-03-08 11:48:53 +01:00
$sql = " ALTER TABLE " . $table ;
2011-03-08 11:33:43 +01:00
$sql .= " MODIFY COLUMN " . $field_name . " " . $field_desc [ 'type' ];
2020-06-29 13:48:00 +02:00
if ( in_array ( $field_desc [ 'type' ], array ( 'double' , 'tinyint' , 'int' , 'varchar' )) && $field_desc [ 'value' ]) {
2020-04-10 10:59:32 +02:00
$sql .= " ( " . $field_desc [ 'value' ] . " ) " ;
2012-11-11 15:10:01 +01:00
}
2011-03-08 11:33:43 +01:00
2021-02-23 22:03:23 +01:00
if ( $field_desc [ 'null' ] == 'not null' || $field_desc [ 'null' ] == 'NOT NULL' ) {
2020-10-31 14:32:18 +01:00
// 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
2021-02-23 22:03:23 +01:00
if ( $field_desc [ 'type' ] == 'varchar' || $field_desc [ 'type' ] == 'text' ) {
2020-10-31 14:32:18 +01:00
$sqlbis = " UPDATE " . $table . " SET " . $field_name . " = ' " . $this -> escape ( $field_desc [ 'default' ] ? $field_desc [ 'default' ] : '' ) . " ' WHERE " . $field_name . " IS NULL " ;
$this -> query ( $sqlbis );
2021-02-23 22:03:23 +01:00
} elseif ( $field_desc [ 'type' ] == 'tinyint' || $field_desc [ 'type' ] == 'int' ) {
2020-10-31 14:32:18 +01:00
$sqlbis = " UPDATE " . $table . " SET " . $field_name . " = " . (( int ) $this -> escape ( $field_desc [ 'default' ] ? $field_desc [ 'default' ] : 0 )) . " WHERE " . $field_name . " IS NULL " ;
$this -> query ( $sqlbis );
}
2017-09-02 15:12:21 +02:00
}
2021-02-23 22:03:23 +01:00
if ( $field_desc [ 'default' ] != '' ) {
if ( $field_desc [ 'type' ] == 'double' || $field_desc [ 'type' ] == 'tinyint' || $field_desc [ 'type' ] == 'int' ) {
$sql .= " DEFAULT " . $this -> escape ( $field_desc [ 'default' ]);
} elseif ( $field_desc [ 'type' ] != 'text' ) {
$sql .= " DEFAULT ' " . $this -> escape ( $field_desc [ 'default' ]) . " ' " ; // Default not supported on text fields
}
2017-09-02 15:12:21 +02:00
}
2012-11-11 15:10:01 +01:00
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2021-02-23 22:03:23 +01:00
if ( ! $this -> query ( $sql )) {
2015-05-12 18:31:12 +02:00
return - 1 ;
2021-02-23 22:03:23 +01:00
}
2011-03-08 11:33:43 +01:00
return 1 ;
}
2011-03-09 03:02:25 +01:00
2020-10-31 14:32:18 +01:00
// phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
2009-01-27 00:52:37 +01:00
/**
2012-01-06 14:51:09 +01:00
* Drop a field from table
2011-09-03 01:09:39 +02:00
*
2012-01-06 14:51:09 +01:00
* @ param string $table Name of table
* @ param string $field_name Name of field to drop
* @ return int < 0 if KO , > 0 if OK
2009-01-27 00:52:37 +01:00
*/
2020-10-31 14:32:18 +01:00
public function DDLDropField ( $table , $field_name )
2009-01-27 00:52:37 +01:00
{
2020-10-31 14:32:18 +01:00
// phpcs:enable
2020-04-10 10:59:32 +02:00
$sql = " ALTER TABLE " . $table . " DROP COLUMN " . $field_name ;
2019-01-27 11:55:16 +01:00
dol_syslog ( $sql , LOG_DEBUG );
2021-02-23 22:03:23 +01:00
if ( ! $this -> query ( $sql )) {
2020-04-10 10:59:32 +02:00
$this -> error = $this -> lasterror ();
2009-01-27 00:52:37 +01:00
return - 1 ;
}
2015-05-12 18:31:12 +02:00
return 1 ;
2009-01-27 00:52:37 +01:00
}
2009-07-03 10:22:06 +02:00
/**
2011-09-03 01:09:39 +02:00
* Return charset used to store data in database
*
* @ return string Charset
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getDefaultCharacterSetDatabase ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( 'SHOW SERVER_ENCODING' );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$liste = $this -> fetch_array ( $resql );
return $liste [ 'server_encoding' ];
2021-02-23 22:03:23 +01:00
} else {
return '' ;
}
2007-05-23 23:10:11 +02:00
}
2009-01-25 18:56:42 +01:00
2009-07-03 10:22:06 +02:00
/**
2011-09-03 01:09:39 +02:00
* Return list of available charset that can be used to store data in database
*
* @ return array List of Charset
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getListOfCharacterSet ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( 'SHOW SERVER_ENCODING' );
2007-08-20 15:53:28 +02:00
$liste = array ();
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2007-08-20 15:53:28 +02:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
while ( $obj = $this -> fetch_object ( $resql )) {
2009-10-22 19:15:09 +02:00
$liste [ $i ][ 'charset' ] = $obj -> server_encoding ;
$liste [ $i ][ 'description' ] = 'Default database charset' ;
2009-01-25 18:56:42 +01:00
$i ++ ;
}
2009-10-22 19:15:09 +02:00
$this -> free ( $resql );
} else {
return null ;
}
return $liste ;
2007-08-20 15:53:28 +02:00
}
2009-01-25 18:56:42 +01:00
2009-07-03 10:22:06 +02:00
/**
2011-09-03 01:09:39 +02:00
* Return collation used in database
*
* @ return string Collation value
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getDefaultCollationDatabase ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( 'SHOW LC_COLLATE' );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$liste = $this -> fetch_array ( $resql );
2016-05-17 23:14:30 +02:00
return $liste [ 'lc_collate' ];
2021-02-23 22:03:23 +01:00
} else {
return '' ;
}
2007-08-20 15:53:28 +02:00
}
2009-01-25 18:56:42 +01:00
2009-07-03 10:22:06 +02:00
/**
2011-09-03 01:09:39 +02:00
* Return list of available collation that can be used for database
*
* @ return array Liste of Collation
2009-07-03 10:22:06 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getListOfCollation ()
2009-10-22 19:15:09 +02:00
{
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( 'SHOW LC_COLLATE' );
2007-08-20 15:53:28 +02:00
$liste = array ();
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2007-08-20 15:53:28 +02:00
$i = 0 ;
2021-02-23 22:03:23 +01:00
while ( $obj = $this -> fetch_object ( $resql )) {
2009-10-22 19:15:09 +02:00
$liste [ $i ][ 'collation' ] = $obj -> lc_collate ;
2009-01-25 18:56:42 +01:00
$i ++ ;
}
2009-10-22 19:15:09 +02:00
$this -> free ( $resql );
} else {
return null ;
}
return $liste ;
2007-08-20 15:53:28 +02:00
}
2009-01-25 18:56:42 +01:00
2009-11-29 20:32:16 +01:00
/**
2011-08-04 15:58:14 +02:00
* Return full path of dump program
2011-09-03 01:09:39 +02:00
*
2011-08-04 15:58:14 +02:00
* @ return string Full path of dump program
2009-11-29 20:32:16 +01:00
*/
2020-10-31 14:32:18 +01:00
public function getPathOfDump ()
2009-11-29 20:32:16 +01:00
{
2020-04-10 10:59:32 +02:00
$fullpathofdump = '/pathtopgdump/pg_dump' ;
2009-11-29 20:32:16 +01:00
2021-02-23 22:03:23 +01:00
if ( file_exists ( '/usr/bin/pg_dump' )) {
2020-10-31 14:32:18 +01:00
$fullpathofdump = '/usr/bin/pg_dump' ;
2020-05-21 15:05:19 +02:00
} else {
2020-10-31 14:32:18 +01:00
// TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
$resql = $this -> query ( 'SHOW data_directory' );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$liste = $this -> fetch_array ( $resql );
$basedir = $liste [ 'data_directory' ];
$fullpathofdump = preg_replace ( '/data$/' , 'bin' , $basedir ) . '/pg_dump' ;
}
2009-11-29 20:32:16 +01:00
}
return $fullpathofdump ;
}
2020-10-31 14:32:18 +01:00
/**
* Return full path of restore program
*
* @ return string Full path of restore program
*/
public function getPathOfRestore ()
2009-11-29 20:32:16 +01:00
{
2014-09-17 17:38:07 +02:00
//$tool='pg_restore';
2020-04-10 10:59:32 +02:00
$tool = 'psql' ;
2011-01-10 02:40:49 +01:00
2020-04-10 10:59:32 +02:00
$fullpathofdump = '/pathtopgrestore/' . $tool ;
2014-09-17 17:38:07 +02:00
2021-02-23 22:03:23 +01:00
if ( file_exists ( '/usr/bin/' . $tool )) {
2020-10-31 14:32:18 +01:00
$fullpathofdump = '/usr/bin/' . $tool ;
} else {
// TODO L'utilisateur de la base doit etre un superadmin pour lancer cette commande
$resql = $this -> query ( 'SHOW data_directory' );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
2020-10-31 14:32:18 +01:00
$liste = $this -> fetch_array ( $resql );
$basedir = $liste [ 'data_directory' ];
$fullpathofdump = preg_replace ( '/data$/' , 'bin' , $basedir ) . '/' . $tool ;
}
}
2009-11-29 20:32:16 +01:00
2011-01-10 02:40:49 +01:00
return $fullpathofdump ;
2009-11-29 20:32:16 +01:00
}
2010-05-09 15:45:27 +02:00
/**
2014-02-24 09:52:48 +01:00
* Return value of server parameters
2011-09-03 01:09:39 +02:00
*
2014-02-24 09:52:48 +01:00
* @ param string $filter Filter list on a particular value
* @ return array Array of key - values ( key => value )
2010-05-09 15:45:27 +02:00
*/
2020-10-31 14:32:18 +01:00
public function getServerParametersValues ( $filter = '' )
2010-05-09 15:45:27 +02:00
{
2020-04-10 10:59:32 +02:00
$result = array ();
2010-05-09 15:45:27 +02:00
2020-04-10 10:59:32 +02:00
$resql = 'select name,setting from pg_settings' ;
2021-02-23 22:03:23 +01:00
if ( $filter ) {
$resql .= " WHERE name = ' " . $this -> escape ( $filter ) . " ' " ;
}
2020-04-10 10:59:32 +02:00
$resql = $this -> query ( $resql );
2021-02-23 22:03:23 +01:00
if ( $resql ) {
while ( $obj = $this -> fetch_object ( $resql )) {
$result [ $obj -> name ] = $obj -> setting ;
}
2010-05-09 15:45:27 +02:00
}
return $result ;
}
2014-02-21 14:41:00 +01:00
/**
2014-02-24 09:52:48 +01:00
* Return value of server status
2014-02-21 14:41:00 +01:00
*
2014-02-24 09:52:48 +01:00
* @ param string $filter Filter list on a particular value
* @ return array Array of key - values ( key => value )
2014-02-21 14:41:00 +01:00
*/
2020-10-31 14:32:18 +01:00
public function getServerStatusValues ( $filter = '' )
2014-02-21 14:41:00 +01:00
{
2014-02-24 09:52:48 +01:00
/* This is to return current running requests .
$sql = 'SELECT datname,procpid,current_query FROM pg_stat_activity ORDER BY procpid' ;
2021-02-23 22:03:23 +01:00
if ( $filter ) $sql .= " LIKE ' " . $this -> escape ( $filter ) . " ' " ;
$resql = $this -> query ( $sql );
if ( $resql )
{
$obj = $this -> fetch_object ( $resql );
$result [ $obj -> Variable_name ] = $obj -> Value ;
}
2014-02-24 09:52:48 +01:00
*/
2014-02-21 14:41:00 +01:00
2014-02-24 09:52:48 +01:00
return array ();
2014-02-21 14:41:00 +01:00
}
2004-08-24 09:02:32 +02:00
}