From 207fa671b10e4458670674d2df88bc0badd676c1 Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 25 Feb 2015 09:04:11 +0100 Subject: [PATCH 01/11] Mise en place de l'initialisation de la base avec PDO SQlite --- .gitattributes | 66 +++++++-------- INSTALL | 12 +-- htdocs/conf/phpinfo.php | 5 ++ htdocs/core/db/sqlite.class.php | 83 +++++++++++++++++-- htdocs/core/modules/DolibarrModules.class.php | 2 +- htdocs/install/etape2.php | 3 + htdocs/install/fileconf.php | 2 +- htdocs/install/sqlite/functions/functions.sql | 0 htdocs/install/sqlite/index.html | 0 index.php | 2 + 10 files changed, 127 insertions(+), 48 deletions(-) create mode 100644 htdocs/conf/phpinfo.php create mode 100644 htdocs/install/sqlite/functions/functions.sql create mode 100644 htdocs/install/sqlite/index.html create mode 100644 index.php diff --git a/.gitattributes b/.gitattributes index c5785ace780..0bea828e011 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,33 +1,33 @@ -# Set default behaviour, in case users don't have core.autocrlf set. -# More info: https://help.github.com/articles/dealing-with-line-endings -* text=auto - - -# Explicitly declare text files we want to always be normalized and converted -# to native line endings on checkout. -*.php text eol=lf -*.pl text eol=lf -*.sql text eol=lf -*.htm text eol=lf -*.html text eol=lf -*.js text eol=lf -*.css text eol=lf -*.lang text eol=lf -*.txt text eol=lf -*.md text eol=lf -*.pp text eol=lf -*.sh text eol=lf -*.yaml text eol=lf - -.bash_aliases text eol=lf - -# Denote all files that are truly binary and should not be modified. -*.bmp binary -*.ico binary -*.png binary -*.jpg binary -*.odt binary -*.odf binary -*.frm binary -*.MYD binary -*.MYI binary +# Set default behaviour, in case users don't have core.autocrlf set. +# More info: https://help.github.com/articles/dealing-with-line-endings +* text=auto + + +# Explicitly declare text files we want to always be normalized and converted +# to native line endings on checkout. +*.php text eol=lf +*.pl text eol=lf +*.sql text eol=lf +*.htm text eol=lf +*.html text eol=lf +*.js text eol=lf +*.css text eol=lf +*.lang text eol=lf +*.txt text eol=lf +*.md text eol=lf +*.pp text eol=lf +*.sh text eol=lf +*.yaml text eol=lf + +.bash_aliases text eol=lf + +# Denote all files that are truly binary and should not be modified. +*.bmp binary +*.ico binary +*.png binary +*.jpg binary +*.odt binary +*.odf binary +*.frm binary +*.MYD binary +*.MYI binary diff --git a/INSTALL b/INSTALL index 584c3f04713..9f2fb214281 100644 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,6 @@ -INSTALL -------- - -English: See README.md file. - -French: Voir fichier README-FR.md. +INSTALL +------- + +English: See README.md file. + +French: Voir fichier README-FR.md. diff --git a/htdocs/conf/phpinfo.php b/htdocs/conf/phpinfo.php new file mode 100644 index 00000000000..179bd651458 --- /dev/null +++ b/htdocs/conf/phpinfo.php @@ -0,0 +1,5 @@ +Go back to index +| ">Refresh +

+ + \ No newline at end of file diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index b16114a773f..786bf435fcf 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -40,6 +40,12 @@ class DoliDBSqlite extends DoliDB //! Resultset of last query private $_results; + /** + * Indique que les fonctions personnalisées sont définies + * @var boolean + */ + private static $customFunctionsDefined = false; + /** * Constructor. * This create an opened connexion to a database server and eventually to a database @@ -153,7 +159,7 @@ class DoliDBSqlite extends DoliDB // 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); + $newline=preg_replace('/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i','\\1 \\2 integer PRIMARY KEY AUTOINCREMENT',$line); //$line = "-- ".$line." replaced by --\n".$newline; $line=$newline; } @@ -242,10 +248,17 @@ class DoliDBSqlite extends DoliDB $line = "-- ".$line." replaced by --\n"; $line.= "CREATE ".(preg_match('/UNIQUE/',$reg[2])?'UNIQUE ':'')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")"; } - } + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$line, $reg)) { + // Pour l'instant les contraintes ne sont pas créées + dol_syslog(get_class().'::query line emptied'); + $line = 'SELECT 0;'; - // To have postgresql case sensitive - $line=str_replace(' LIKE \'',' ILIKE \'',$line); + } + + //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) { + //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line); + //} + } // Delete using criteria on other table must not declare twice the deleted table // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable @@ -387,7 +400,53 @@ class DoliDBSqlite extends DoliDB $this->error = 0; // Convert MySQL syntax to SQLite syntax - $query=$this->convertSQLFromMysql($query,$type); + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$query, $reg)) { + // Ajout d'une clef étrangère à la table + // procédure de remplacement de la table pour ajouter la contrainte + // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid) + // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)) + $foreignFields = $reg[5]; + $foreignTable = $reg[4]; + $localfields = $reg[3]; + $constraintname=trim($reg[2]); + $tablename=trim($reg[1]); + + $res = $this->db->query("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); + $descTable = $res->fetchColumn(); + $res->closeCursor(); + + // 1- Renommer la table avec un nom temporaire + $res = $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); + $res->closeCursor(); + + // 2- Recréer la table avec la contrainte ajoutée + + // on bricole la requete pour ajouter la contrainte + $descTable = substr($descTable, 0, strlen($descTable) - 1); + $descTable .= ", CONSTRAINT " . $constraintname . " FOREIGN KEY (" . $localfields . ") REFERENCES " .$foreignTable . "(" . $foreignFields . ")"; + + // fermeture de l'instruction + $descTable .= ')'; + + // Création proprement dite de la table + $res = $this->query($descTable); + $res->closeCursor(); + + // 3- Transférer les données + $res = $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); + $res->closeCursor(); + + + // 4- Supprimer la table temporaire + $res = $this->query('DROP TABLE tmp_' . $tablename); + $res->closeCursor(); + + // dummy statement + $query="SELECT 0"; + + } else { + $query=$this->convertSQLFromMysql($query,$type); + } //print "After convertSQLFromMysql:\n".$query."
\n"; dol_syslog('sql='.$query, LOG_DEBUG); @@ -487,7 +546,11 @@ class DoliDBSqlite extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - return $resultset->rowCount(); + if (preg_match("/^SELECT/i", $resultset->queryString)) { + $res = $this->db->query("SELECT count(*) FROM (" . $resultset->queryString . ") q"); + return $res->fetchColumn(); + } + return $resultset->rowCount(); } /** @@ -529,7 +592,12 @@ class DoliDBSqlite extends DoliDB */ function escape($stringtoencode) { - return $this->db->quote($stringtoencode); + $ret = $this->db->quote($stringtoencode); + $l = strlen($ret); + if ($l >= 2) { + return substr($ret, 1, $l -2); + } + return ''; } /** @@ -1135,5 +1203,6 @@ class DoliDBSqlite extends DoliDB return $result; } + } diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 17b8b8e8def..0b0ceb5460c 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -1012,7 +1012,7 @@ abstract class DolibarrModules if ($resql) { $obj=$this->db->fetch_object($resql); - if (! empty($obj->value) && ! empty($this->rights)) + if ($obj !== null && ! empty($obj->value) && ! empty($this->rights)) { // Si module actif foreach ($this->rights as $key => $value) diff --git a/htdocs/install/etape2.php b/htdocs/install/etape2.php index 1f6c5244d84..d934f79f0af 100644 --- a/htdocs/install/etape2.php +++ b/htdocs/install/etape2.php @@ -51,6 +51,8 @@ if ($dolibarr_main_db_type == "mysql") $choix=1; if ($dolibarr_main_db_type == "mysqli") $choix=1; if ($dolibarr_main_db_type == "pgsql") $choix=2; if ($dolibarr_main_db_type == "mssql") $choix=3; +if ($dolibarr_main_db_type == "sqlite") $choix=4; + //if (empty($choix)) dol_print_error('','Database type '.$dolibarr_main_db_type.' not supported into etape2.php page'); // Now we load forced value from install.forced.php file. @@ -411,6 +413,7 @@ if ($action == "set") if ($choix==1) $dir = "mysql/functions/"; elseif ($choix==2) $dir = "pgsql/functions/"; elseif ($choix==3) $dir = "mssql/functions/"; + elseif ($choix==4) { $dir = "sqlite/functions/"; } // Creation donnees $file = "functions.sql"; diff --git a/htdocs/install/fileconf.php b/htdocs/install/fileconf.php index 2c6a5730100..49b80eb1b6b 100644 --- a/htdocs/install/fileconf.php +++ b/htdocs/install/fileconf.php @@ -306,7 +306,7 @@ if (! empty($force_install_message)) $class='DoliDB'.ucfirst($type); include_once $dir."/".$file; - if ($type == 'sqlite') continue; // We hide sqlite because support can't be complete unti sqlit does not manage foreign key creation after table creation + //if ($type == 'sqlite') continue; // We hide sqlite because support can't be complete unti sqlit does not manage foreign key creation after table creation // Version min of database $versionbasemin=explode('.',$class::VERSIONMIN); diff --git a/htdocs/install/sqlite/functions/functions.sql b/htdocs/install/sqlite/functions/functions.sql new file mode 100644 index 00000000000..e69de29bb2d diff --git a/htdocs/install/sqlite/index.html b/htdocs/install/sqlite/index.html new file mode 100644 index 00000000000..e69de29bb2d diff --git a/index.php b/index.php new file mode 100644 index 00000000000..c59480bf4de --- /dev/null +++ b/index.php @@ -0,0 +1,2 @@ + Date: Wed, 25 Feb 2015 14:31:41 +0100 Subject: [PATCH 02/11] =?UTF-8?q?Utilisation=20de=20la=20librairie=20Sqlit?= =?UTF-8?q?e3=20et=20cr=C3=A9ation=20de=20fonctions=20personnalis=C3=A9es?= =?UTF-8?q?=20pour=20la=20compatibilit=C3=A9=20avec=20MySQL.=20Certains=20?= =?UTF-8?q?formats=20de=20date=20ne=20sont=20pas=20compl=C3=A8tement=20pri?= =?UTF-8?q?s=20en=20compte.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/db/sqlite.class.php | 168 +++++++++++++++++++++++--------- 1 file changed, 124 insertions(+), 44 deletions(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 786bf435fcf..d1a114a3330 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -34,18 +34,12 @@ class DoliDBSqlite extends DoliDB //! Database type public $type='sqlite'; //! Database label - const LABEL='PDO Sqlite'; + const LABEL='Sqlite3'; //! Version min database const VERSIONMIN='3.0.0'; //! Resultset of last query private $_results; - /** - * Indique que les fonctions personnalisées sont définies - * @var boolean - */ - private static $customFunctionsDefined = false; - /** * Constructor. * This create an opened connexion to a database server and eventually to a database @@ -102,7 +96,10 @@ class DoliDBSqlite extends DoliDB $this->database_selected = 1; $this->database_name = $name; - $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->addCustomFunction('IF'); + $this->addCustomFunction('MONTH'); + $this->addCustomFunction('date_format'); + //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } else { @@ -322,14 +319,16 @@ class DoliDBSqlite extends DoliDB if (empty($dir)) $dir=DOL_DATA_ROOT; // With sqlite, port must be in connect parameters //if (! $newport) $newport=3306; + $database_name = $dir.'/database_'.$name.'.sdb'; try { /*** connect to SQLite database ***/ - $this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); - $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); + $this->db = new SQLite3($database_name); + //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } - catch(PDOException $e) + catch(Exception $e) { - $this->error='PDO SQLITE '.$e->getMessage().' current dir='.$dir.'/database_'.$name.'.sdb'; + $this->error= self::LABEL.' '.$e->getMessage().' current dir='.$database_name; return ''; } @@ -345,9 +344,7 @@ class DoliDBSqlite extends DoliDB */ function getVersion() { - $resql=$this->query('SELECT sqlite_version() as sqliteversion'); - $row=$this->fetch_row($resql); - return $row[0]; + return $this->db->version(); } /** @@ -376,6 +373,7 @@ class DoliDBSqlite extends DoliDB { if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR); $this->connected=0; + $this->db->close(); $this->db=null; // Clean this->db return true; } @@ -411,13 +409,10 @@ class DoliDBSqlite extends DoliDB $constraintname=trim($reg[2]); $tablename=trim($reg[1]); - $res = $this->db->query("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); - $descTable = $res->fetchColumn(); - $res->closeCursor(); + $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); // 1- Renommer la table avec un nom temporaire - $res = $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); - $res->closeCursor(); + $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); // 2- Recréer la table avec la contrainte ajoutée @@ -429,17 +424,13 @@ class DoliDBSqlite extends DoliDB $descTable .= ')'; // Création proprement dite de la table - $res = $this->query($descTable); - $res->closeCursor(); + $this->query($descTable); // 3- Transférer les données - $res = $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); - $res->closeCursor(); - + $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); // 4- Supprimer la table temporaire - $res = $this->query('DROP TABLE tmp_' . $tablename); - $res->closeCursor(); + $this->query('DROP TABLE tmp_' . $tablename); // dummy statement $query="SELECT 0"; @@ -455,8 +446,9 @@ class DoliDBSqlite extends DoliDB try { //$ret = $this->db->exec($query); $ret = $this->db->query($query); // $ret is a PDO object + $ret->queryString = $query; } - catch(PDOException $e) + catch(Exception $e) { $this->error=$e->getMessage(); } @@ -497,7 +489,11 @@ class DoliDBSqlite extends DoliDB { // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion if (! is_object($resultset)) { $resultset=$this->_results; } - return $resultset->fetch(PDO::FETCH_OBJ); + //return $resultset->fetch(PDO::FETCH_OBJ); + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (object)$ret; + } } @@ -511,7 +507,11 @@ class DoliDBSqlite extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - return $resultset->fetch(PDO::FETCH_ASSOC); + //return $resultset->fetch(PDO::FETCH_ASSOC); + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (array)$ret; + } } /** @@ -526,7 +526,7 @@ class DoliDBSqlite extends DoliDB if (! is_bool($resultset)) { if (! is_object($resultset)) { $resultset=$this->_results; } - return $resultset->fetch(PDO::FETCH_NUM); + return $resultset->fetchArray(SQLITE3_NUM); } else { @@ -547,10 +547,9 @@ class DoliDBSqlite extends DoliDB // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } if (preg_match("/^SELECT/i", $resultset->queryString)) { - $res = $this->db->query("SELECT count(*) FROM (" . $resultset->queryString . ") q"); - return $res->fetchColumn(); + return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q"); } - return $resultset->rowCount(); + return 0; } /** @@ -564,9 +563,12 @@ class DoliDBSqlite extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } + if (preg_match("/^SELECT/i", $resultset->queryString)) { + return $this->num_rows($resultset); + } // mysql necessite un link de base pour cette fonction contrairement // a pqsql qui prend un resultset - return $resultset->rowCount(); + return $this->db->changes(); } @@ -581,7 +583,7 @@ class DoliDBSqlite extends DoliDB // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } // Si resultset en est un, on libere la memoire - if (is_object($resultset)) $resultset->closeCursor(); + if ($resultset && is_object($resultset)) $resultset->finalize(); } /** @@ -592,12 +594,7 @@ class DoliDBSqlite extends DoliDB */ function escape($stringtoencode) { - $ret = $this->db->quote($stringtoencode); - $l = strlen($ret); - if ($l >= 2) { - return substr($ret, 1, $l -2); - } - return ''; + return Sqlite3::escapeString($stringtoencode); } /** @@ -645,7 +642,7 @@ class DoliDBSqlite extends DoliDB { return $errorcode_map[$this->db->errorCode()]; }*/ - $errno=$this->db->errorCode(); + $errno=$this->db->lastErrorCode(); if ($errno=='HY000') { if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS'; @@ -687,7 +684,7 @@ class DoliDBSqlite extends DoliDB */ function last_insert_id($tab,$fieldid='rowid') { - return $this->db->lastInsertId(); + return $this->db->lastInsertRowId(); } /** @@ -1204,5 +1201,88 @@ class DoliDBSqlite extends DoliDB return $result; } + private function addCustomFunction($name) { + if ($this->db) { + $localname = __CLASS__ . '::' . 'db_' . $name; + $reflectClass = new ReflectionClass(__CLASS__); + $reflectFunction = $reflectClass->getMethod('db_' . $name); + $arg_count = $reflectFunction->getNumberOfParameters(); + if (!$this->db->createFunction($name, $localname , $arg_count)) { + $this->error = "unable to create custom function '$name'"; + } + } + return 0; + } + + public static function db_MONTH($date) { + return date('n', strtotime($date)); + } + + public static function db_date_format($date, $format) { + static $mysql_replacement; + if (! isset($mysql_replacement)) { + $mysql_replacement = array( + '%' => '%', + 'a' => 'D', + 'b' => 'M', + 'c' => 'n', + 'D' => 'jS', + 'd' => 'd', + 'e' => 'j', + 'f' => 'u', + 'H' => 'H', + 'h' => 'h', + 'I' => 'h', + 'i' => 'i', + 'j' => 'z', + 'k' => 'H', + 'l' => 'g', + 'M' => 'F', + 'm' => 'm', + 'p' => 'A', + 'r' => 'h:i:sA', + 'S' => 's', + 's' => 's', + 'T' => 'H:i:s', + 'U' => '', //? + 'u' => '', //? + 'V' => '', //? + 'v' => '', //? + 'W' => 'l', + 'w' => 'w', + 'X' => '', //? + 'x' => '', //? + 'Y' => 'Y', + 'y' => 'y', + ); + } + + $fmt = ''; + $lg = strlen($format); + $state = 0; + for($idx = 0; $idx < $lg; ++$idx) { + $char = $format[$idx]; + if ($state == 0) { + if ($char == '%') { + $state = 1; + } else { + $fmt .= $char; + } + } + elseif ($state == 1) { + if (array_key_exists($char, $mysql_replacement)) { + $fmt .= $mysql_replacement[$char]; + } else { + $fmt .= $char; + } + $state = 0; + } + } + return date($fmt, strtotime($date)); + } + + public static function db_IF($test, $true_part, $false_part) { + return ( $test ) ? $true_part : $false_part; + } } From 9839420a6870f9c0fed0675528a20f171a8fd182 Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 25 Feb 2015 15:44:06 +0100 Subject: [PATCH 03/11] Correction de la gestion d'erreur. --- htdocs/core/db/sqlite.class.php | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index d1a114a3330..6a2f8ca955c 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -344,7 +344,7 @@ class DoliDBSqlite extends DoliDB */ function getVersion() { - return $this->db->version(); + return $this->db->version()['versionString']; } /** @@ -446,7 +446,9 @@ class DoliDBSqlite extends DoliDB try { //$ret = $this->db->exec($query); $ret = $this->db->query($query); // $ret is a PDO object - $ret->queryString = $query; + if ($ret) { + $ret->queryString = $query; + } } catch(Exception $e) { @@ -1201,6 +1203,12 @@ class DoliDBSqlite extends DoliDB return $result; } + /** + * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees. + * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être + * statique et publique. Le nombre de parametres est determine automatiquement. + * @param string $name Le nom de la fonction a definir dans Sqlite + */ private function addCustomFunction($name) { if ($this->db) { $localname = __CLASS__ . '::' . 'db_' . $name; @@ -1211,13 +1219,24 @@ class DoliDBSqlite extends DoliDB $this->error = "unable to create custom function '$name'"; } } - return 0; } + /** + * Cette fonction est l'equivalent de la fonction MONTH de MySql. + * @param string $date + * @return integer + */ public static function db_MONTH($date) { return date('n', strtotime($date)); } + /** + * Cette fonction est l'equivelent de la fonction date_format de MySQL. + * @staticvar string $mysql_replacement Les symboles formatage a remplacer + * @param string $date la date dans un format ISO + * @param string $format la chaine de formatage + * @return string La date formatee. + */ public static function db_date_format($date, $format) { static $mysql_replacement; if (! isset($mysql_replacement)) { @@ -1281,6 +1300,13 @@ class DoliDBSqlite extends DoliDB return date($fmt, strtotime($date)); } + /** + * Equivalent de la fonction MySQL IF + * @param boolean $test Le resultat du test + * @param mixed $true_part Partie a retourner si vrai + * @param mixed $false_part Partie a retourner si faux + * @return mixed Partie selectionnee en fonction du test + */ public static function db_IF($test, $true_part, $false_part) { return ( $test ) ? $true_part : $false_part; } From 9fdb4a0ee3bc6e11580237290c1620ba6b739676 Mon Sep 17 00:00:00 2001 From: guillaume Date: Wed, 25 Feb 2015 16:37:00 +0100 Subject: [PATCH 04/11] Modification des attributs --- .gitattributes | 66 +++++++++++++++++++++++++------------------------- INSTALL | 12 ++++----- index.php | 2 +- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.gitattributes b/.gitattributes index 0bea828e011..c5785ace780 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,33 +1,33 @@ -# Set default behaviour, in case users don't have core.autocrlf set. -# More info: https://help.github.com/articles/dealing-with-line-endings -* text=auto - - -# Explicitly declare text files we want to always be normalized and converted -# to native line endings on checkout. -*.php text eol=lf -*.pl text eol=lf -*.sql text eol=lf -*.htm text eol=lf -*.html text eol=lf -*.js text eol=lf -*.css text eol=lf -*.lang text eol=lf -*.txt text eol=lf -*.md text eol=lf -*.pp text eol=lf -*.sh text eol=lf -*.yaml text eol=lf - -.bash_aliases text eol=lf - -# Denote all files that are truly binary and should not be modified. -*.bmp binary -*.ico binary -*.png binary -*.jpg binary -*.odt binary -*.odf binary -*.frm binary -*.MYD binary -*.MYI binary +# Set default behaviour, in case users don't have core.autocrlf set. +# More info: https://help.github.com/articles/dealing-with-line-endings +* text=auto + + +# Explicitly declare text files we want to always be normalized and converted +# to native line endings on checkout. +*.php text eol=lf +*.pl text eol=lf +*.sql text eol=lf +*.htm text eol=lf +*.html text eol=lf +*.js text eol=lf +*.css text eol=lf +*.lang text eol=lf +*.txt text eol=lf +*.md text eol=lf +*.pp text eol=lf +*.sh text eol=lf +*.yaml text eol=lf + +.bash_aliases text eol=lf + +# Denote all files that are truly binary and should not be modified. +*.bmp binary +*.ico binary +*.png binary +*.jpg binary +*.odt binary +*.odf binary +*.frm binary +*.MYD binary +*.MYI binary diff --git a/INSTALL b/INSTALL index 9f2fb214281..584c3f04713 100644 --- a/INSTALL +++ b/INSTALL @@ -1,6 +1,6 @@ -INSTALL -------- - -English: See README.md file. - -French: Voir fichier README-FR.md. +INSTALL +------- + +English: See README.md file. + +French: Voir fichier README-FR.md. diff --git a/index.php b/index.php index c59480bf4de..e4341bb53ec 100644 --- a/index.php +++ b/index.php @@ -1,2 +1,2 @@ - Date: Fri, 27 Feb 2015 14:06:53 +0100 Subject: [PATCH 05/11] Correction de la gestion d'erreur. --- htdocs/core/db/sqlite.class.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 6a2f8ca955c..3ec2a9397b7 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -452,7 +452,7 @@ class DoliDBSqlite extends DoliDB } catch(Exception $e) { - $this->error=$e->getMessage(); + $this->error=$this->db->lastErrorMsg(); } if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query)) @@ -645,7 +645,7 @@ class DoliDBSqlite extends DoliDB return $errorcode_map[$this->db->errorCode()]; }*/ $errno=$this->db->lastErrorCode(); - if ($errno=='HY000') + if ($errno=='HY000' || $errno == 0) { if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS'; elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'; @@ -656,6 +656,9 @@ class DoliDBSqlite extends DoliDB if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; } + if ($errno > 1) { + // TODO Voir la liste des messages d'erreur + } return ($errno?'DB_ERROR_'.$errno:'0'); } From 8de170bfc2ed18fdb3817f809eadf4d4d3913b82 Mon Sep 17 00:00:00 2001 From: guillaume Date: Tue, 3 Mar 2015 13:06:20 +0100 Subject: [PATCH 06/11] Ajout de fonctions pour le traitement des dates avec SQLITE. --- htdocs/core/db/sqlite.class.php | 156 ++++++++++++++++++++++++++++++-- 1 file changed, 146 insertions(+), 10 deletions(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 3ec2a9397b7..82de9b32103 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -40,6 +40,11 @@ class DoliDBSqlite extends DoliDB //! Resultset of last query private $_results; + const WEEK_MONDAY_FIRST=1; + const WEEK_YEAR = 2; + const WEEK_FIRST_WEEKDAY=4; + + /** * Constructor. * This create an opened connexion to a database server and eventually to a database @@ -98,6 +103,11 @@ class DoliDBSqlite extends DoliDB $this->addCustomFunction('IF'); $this->addCustomFunction('MONTH'); + $this->addCustomFunction('CURTIME'); + $this->addCustomFunction('CURDATE'); + $this->addCustomFunction('WEEK', 1); + $this->addCustomFunction('WEEK', 2); + $this->addCustomFunction('WEEKDAY'); $this->addCustomFunction('date_format'); //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } @@ -1212,12 +1222,14 @@ class DoliDBSqlite extends DoliDB * statique et publique. Le nombre de parametres est determine automatiquement. * @param string $name Le nom de la fonction a definir dans Sqlite */ - private function addCustomFunction($name) { + private function addCustomFunction($name, $arg_count = -1) { if ($this->db) { $localname = __CLASS__ . '::' . 'db_' . $name; $reflectClass = new ReflectionClass(__CLASS__); $reflectFunction = $reflectClass->getMethod('db_' . $name); - $arg_count = $reflectFunction->getNumberOfParameters(); + if ($arg_count < 0) { + $arg_count = $reflectFunction->getNumberOfParameters(); + } if (!$this->db->createFunction($name, $localname , $arg_count)) { $this->error = "unable to create custom function '$name'"; } @@ -1233,6 +1245,32 @@ class DoliDBSqlite extends DoliDB return date('n', strtotime($date)); } + /** + * calcule du numéro de semaine + * + * @param string date + * @param int mode + */ + public static function db_WEEK($date, $mode = 0) { + $arr = date_parse($date); + $calc_year = 0; + return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year); + } + + public static function db_CURDATE() { + return date('Y-m-d'); + } + + public static function db_CURTIME() { + return date('H:i:s'); + } + + public static function db_WEEKDAY($date) { + $arr = date_parse($date); + return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0); + + } + /** * Cette fonction est l'equivelent de la fonction date_format de MySQL. * @staticvar string $mysql_replacement Les symboles formatage a remplacer @@ -1256,24 +1294,17 @@ class DoliDBSqlite extends DoliDB 'h' => 'h', 'I' => 'h', 'i' => 'i', - 'j' => 'z', 'k' => 'H', 'l' => 'g', 'M' => 'F', 'm' => 'm', 'p' => 'A', - 'r' => 'h:i:sA', + 'r' => 'h:i:s A', 'S' => 's', 's' => 's', 'T' => 'H:i:s', - 'U' => '', //? - 'u' => '', //? - 'V' => '', //? - 'v' => '', //? 'W' => 'l', 'w' => 'w', - 'X' => '', //? - 'x' => '', //? 'Y' => 'Y', 'y' => 'y', ); @@ -1282,6 +1313,11 @@ class DoliDBSqlite extends DoliDB $fmt = ''; $lg = strlen($format); $state = 0; + $timestamp = strtotime($date); + $yday = date('z', $timestamp); + $month = (integer)date("n", $timestamp); + $year = (integer)date("Y", $timestamp); + $day = (integer)date("d", $timestamp); for($idx = 0; $idx < $lg; ++$idx) { $char = $format[$idx]; if ($state == 0) { @@ -1295,6 +1331,32 @@ class DoliDBSqlite extends DoliDB if (array_key_exists($char, $mysql_replacement)) { $fmt .= $mysql_replacement[$char]; } else { + $calc_year = 0; + switch ($char) { + case 'j': // day of the year 001 - OK + $char = sprintf("%03d", $yday+1); + break; + case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year)); + break; + case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); + break; + case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche - KO + $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); + break; + case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi - OK + $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); + break; + case 'X': + self::calc_week($year, $month, $day, 6, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + case 'x': + self::calc_week($year, $month, $day, 3, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + } $fmt .= $char; } $state = 0; @@ -1313,5 +1375,79 @@ class DoliDBSqlite extends DoliDB public static function db_IF($test, $true_part, $false_part) { return ( $test ) ? $true_part : $false_part; } + + // Adapté de mytime.c des sources de mariadb + // fonction calc_daynr + private static function calc_daynr($year, $month, $day) { + $y = $year; + if ($y == 0 && $month == 0) return 0; + $num = (365* $y + 31 * ($month - 1) + $day); + if ($month <= 2) { + $y--; } + else { + $num -= floor(($month * 4 + 23) / 10); + } + $temp = floor(($y / 100 + 1) * 3 / 4); + return $num + floor($y / 4) - $temp; + } + + private static function calc_weekday($daynr, $sunday_first_day_of_week) { + $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7); + return $ret; + } + + private static function calc_days_in_year($year) + { + return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365); + } + + private static function week_mode($mode) { + $week_format= ($mode & 7); + if (!($week_format & self::WEEK_MONDAY_FIRST)) { + $week_format^= self::WEEK_FIRST_WEEKDAY; + } + return $week_format; + } + + + private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) { + $daynr=self::calc_daynr($year,$month,$day); + $first_daynr=self::calc_daynr($year,1,1); + $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0; + $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0; + $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0; + + $weekday=self::calc_weekday($first_daynr, !$monday_first); + $calc_year=$year; + + if ($month == 1 && $day <= 7-$weekday) + { + if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) + return 0; + $week_year= 1; + $calc_year--; + $first_daynr-= ($days=self::calc_days_in_year($calc_year)); + $weekday= ($weekday + 53*7- $days) % 7; + } + + if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) { + $days= $daynr - ($first_daynr+ (7-$weekday)); + } + else { + $days= $daynr - ($first_daynr - $weekday); + } + + if ($week_year && $days >= 52*7) + { + $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7; + if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) + { + $calc_year++; + return 1; + } + } + return floor($days/7+1); + } + } From e4edafd42a0ea845d83d9a90509b11594c88646f Mon Sep 17 00:00:00 2001 From: guillaume Date: Tue, 3 Mar 2015 15:21:14 +0100 Subject: [PATCH 07/11] =?UTF-8?q?Ajout=20de=20la=20liste=20des=20param?= =?UTF-8?q?=C3=A8tres=20en=20utilisant=20l'instruction=20PRAGMA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/db/sqlite.class.php | 47 ++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 82de9b32103..513aaf63ac3 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -1183,15 +1183,37 @@ class DoliDBSqlite extends DoliDB function getServerParametersValues($filter='') { $result=array(); + static $pragmas; + if (! isset($pragmas)) { + $pragmas = array( + 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', + 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', + 'compile_options', 'data_version', /*'database_list',*/ + 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count', + 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check', + 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode', + 'max_page_count', 'page_count', 'page_size', 'parser_trace', + 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers', + 'reverse_unordered_selects', 'schema_version', 'user_version', + 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit', + 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', + 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', + 'wal_autocheckpoint', + // TODO poursuivre la liste cf. http://www.sqlite.org/pragma.html + ); + } - $sql='SHOW VARIABLES'; - if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; - $resql=$this->query($sql); - if ($resql) - { - while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; - } - + // TODO prendre en compte le filtre + foreach($pragmas as $var) { + $sql = "PRAGMA $var"; + $resql=$this->query($sql); + if ($resql) + { + $obj = $this->fetch_row($resql); + //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG); + $result[$var] = $obj[0]; + } + } return $result; } @@ -1204,7 +1226,7 @@ class DoliDBSqlite extends DoliDB function getServerStatusValues($filter='') { $result=array(); - + /* $sql='SHOW STATUS'; if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; $resql=$this->query($sql); @@ -1212,6 +1234,7 @@ class DoliDBSqlite extends DoliDB { while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; } + */ return $result; } @@ -1333,7 +1356,7 @@ class DoliDBSqlite extends DoliDB } else { $calc_year = 0; switch ($char) { - case 'j': // day of the year 001 - OK + case 'j': // day of the year 001 $char = sprintf("%03d", $yday+1); break; case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche @@ -1342,10 +1365,10 @@ class DoliDBSqlite extends DoliDB case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); break; - case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche - KO + case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); break; - case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi - OK + case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); break; case 'X': From 1b89b8c808057325e9d5e61a999ba05165057244 Mon Sep 17 00:00:00 2001 From: guillaume Date: Tue, 3 Mar 2015 15:22:52 +0100 Subject: [PATCH 08/11] =?UTF-8?q?Ajout=20de=20la=20liste=20des=20param?= =?UTF-8?q?=C3=A8tres=20en=20utilisant=20l'instruction=20PRAGMA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/core/db/sqlite.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 513aaf63ac3..77e9dcdba54 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -1185,6 +1185,9 @@ class DoliDBSqlite extends DoliDB $result=array(); static $pragmas; if (! isset($pragmas)) { + // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur + // indépendante de la base de données. + // cf. http://www.sqlite.org/pragma.html $pragmas = array( 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', @@ -1199,7 +1202,6 @@ class DoliDBSqlite extends DoliDB 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', 'wal_autocheckpoint', - // TODO poursuivre la liste cf. http://www.sqlite.org/pragma.html ); } From 5a5a2f1bcf4e7bb73eb7485d01a79d102eb65e17 Mon Sep 17 00:00:00 2001 From: guillaume Date: Tue, 3 Mar 2015 15:54:55 +0100 Subject: [PATCH 09/11] =?UTF-8?q?Affichage=20de=20la=20liste=20des=20table?= =?UTF-8?q?s=20dans=20les=20infos=20de=20base=20de=20donn=C3=A9es.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- htdocs/admin/system/database-tables.php | 37 +++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/htdocs/admin/system/database-tables.php b/htdocs/admin/system/database-tables.php index a29c8e66b32..3af715a09b8 100644 --- a/htdocs/admin/system/database-tables.php +++ b/htdocs/admin/system/database-tables.php @@ -66,6 +66,10 @@ else if ($conf->db->type == 'mssql') //$sqls[0] = ""; //$base=3; } +else if ($conf->db->type == 'sqlite') { + //$sql = "SELECT name, type FROM sqlite_master"; + $base = 4; +} if (! $base) @@ -169,6 +173,39 @@ else } print ''; } + + if ($base == 4) + { + print ''; + print ''; + print ''; + print ''; + print "\n"; + + $sql = "SELECT name, type FROM sqlite_master where type='table' and name not like 'sqlite%' ORDER BY name"; + $resql = $db->query($sql); + + if ($resql) + { + $var=True; + while ($row = $db->fetch_row($resql)) { + + $rescount = $db->query("SELECT COUNT(*) FROM " . $row[0]); + if ($rescount) { + $row_count = $db->fetch_row($rescount); + $count = $row_count[0]; + } else { + $count = '?'; + } + + print ""; + print ''; + print ''; + print ''; + } + } + + } } llxFooter(); From 0ef46b06f400487e7350e94fe8d6346ccbdf0df2 Mon Sep 17 00:00:00 2001 From: guillaume Date: Thu, 5 Mar 2015 10:52:37 +0100 Subject: [PATCH 10/11] Sqlite3-PDO restoration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit FR: - Restauration de la version PDO dans sqlite.class.php et désactivation. - Ajout de la classe de base de données Sqlite3 dans sqlite3.class.php EN: - revert of the PDO version of sqlite.class.php and deactivation. - add database class Sqlite3 into sqlite3.class.php. --- htdocs/admin/system/database-tables.php | 3 +- htdocs/core/db/sqlite.class.php | 378 +---- htdocs/core/db/sqlite3.class.php | 1478 +++++++++++++++++ htdocs/install/etape2.php | 4 +- htdocs/install/fileconf.php | 7 +- .../functions/functions.sql | 0 htdocs/install/{sqlite => sqlite3}/index.html | 0 7 files changed, 1540 insertions(+), 330 deletions(-) create mode 100644 htdocs/core/db/sqlite3.class.php rename htdocs/install/{sqlite => sqlite3}/functions/functions.sql (100%) rename htdocs/install/{sqlite => sqlite3}/index.html (100%) diff --git a/htdocs/admin/system/database-tables.php b/htdocs/admin/system/database-tables.php index 3af715a09b8..5ac7292042e 100644 --- a/htdocs/admin/system/database-tables.php +++ b/htdocs/admin/system/database-tables.php @@ -66,7 +66,7 @@ else if ($conf->db->type == 'mssql') //$sqls[0] = ""; //$base=3; } -else if ($conf->db->type == 'sqlite') { +else if ($conf->db->type == 'sqlite3') { //$sql = "SELECT name, type FROM sqlite_master"; $base = 4; } @@ -176,6 +176,7 @@ else if ($base == 4) { + // Sqlite3 print '
'.$langs->trans("TableName").'Rows
'.$row[0].''.$count.'
'; print ''; print ''; diff --git a/htdocs/core/db/sqlite.class.php b/htdocs/core/db/sqlite.class.php index 77e9dcdba54..786bf435fcf 100644 --- a/htdocs/core/db/sqlite.class.php +++ b/htdocs/core/db/sqlite.class.php @@ -34,16 +34,17 @@ class DoliDBSqlite extends DoliDB //! Database type public $type='sqlite'; //! Database label - const LABEL='Sqlite3'; + const LABEL='PDO Sqlite'; //! Version min database const VERSIONMIN='3.0.0'; //! Resultset of last query private $_results; - const WEEK_MONDAY_FIRST=1; - const WEEK_YEAR = 2; - const WEEK_FIRST_WEEKDAY=4; - + /** + * Indique que les fonctions personnalisées sont définies + * @var boolean + */ + private static $customFunctionsDefined = false; /** * Constructor. @@ -101,15 +102,7 @@ class DoliDBSqlite extends DoliDB $this->database_selected = 1; $this->database_name = $name; - $this->addCustomFunction('IF'); - $this->addCustomFunction('MONTH'); - $this->addCustomFunction('CURTIME'); - $this->addCustomFunction('CURDATE'); - $this->addCustomFunction('WEEK', 1); - $this->addCustomFunction('WEEK', 2); - $this->addCustomFunction('WEEKDAY'); - $this->addCustomFunction('date_format'); - //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } else { @@ -329,16 +322,14 @@ class DoliDBSqlite extends DoliDB if (empty($dir)) $dir=DOL_DATA_ROOT; // With sqlite, port must be in connect parameters //if (! $newport) $newport=3306; - $database_name = $dir.'/database_'.$name.'.sdb'; try { /*** connect to SQLite database ***/ - //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); - $this->db = new SQLite3($database_name); - //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + $this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); + $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } - catch(Exception $e) + catch(PDOException $e) { - $this->error= self::LABEL.' '.$e->getMessage().' current dir='.$database_name; + $this->error='PDO SQLITE '.$e->getMessage().' current dir='.$dir.'/database_'.$name.'.sdb'; return ''; } @@ -354,7 +345,9 @@ class DoliDBSqlite extends DoliDB */ function getVersion() { - return $this->db->version()['versionString']; + $resql=$this->query('SELECT sqlite_version() as sqliteversion'); + $row=$this->fetch_row($resql); + return $row[0]; } /** @@ -383,7 +376,6 @@ class DoliDBSqlite extends DoliDB { if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR); $this->connected=0; - $this->db->close(); $this->db=null; // Clean this->db return true; } @@ -419,10 +411,13 @@ class DoliDBSqlite extends DoliDB $constraintname=trim($reg[2]); $tablename=trim($reg[1]); - $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); + $res = $this->db->query("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); + $descTable = $res->fetchColumn(); + $res->closeCursor(); // 1- Renommer la table avec un nom temporaire - $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); + $res = $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); + $res->closeCursor(); // 2- Recréer la table avec la contrainte ajoutée @@ -434,13 +429,17 @@ class DoliDBSqlite extends DoliDB $descTable .= ')'; // Création proprement dite de la table - $this->query($descTable); + $res = $this->query($descTable); + $res->closeCursor(); // 3- Transférer les données - $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); + $res = $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); + $res->closeCursor(); + // 4- Supprimer la table temporaire - $this->query('DROP TABLE tmp_' . $tablename); + $res = $this->query('DROP TABLE tmp_' . $tablename); + $res->closeCursor(); // dummy statement $query="SELECT 0"; @@ -456,13 +455,10 @@ class DoliDBSqlite extends DoliDB try { //$ret = $this->db->exec($query); $ret = $this->db->query($query); // $ret is a PDO object - if ($ret) { - $ret->queryString = $query; - } } - catch(Exception $e) + catch(PDOException $e) { - $this->error=$this->db->lastErrorMsg(); + $this->error=$e->getMessage(); } if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query)) @@ -501,11 +497,7 @@ class DoliDBSqlite extends DoliDB { // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion if (! is_object($resultset)) { $resultset=$this->_results; } - //return $resultset->fetch(PDO::FETCH_OBJ); - $ret = $resultset->fetchArray(SQLITE3_ASSOC); - if ($ret) { - return (object)$ret; - } + return $resultset->fetch(PDO::FETCH_OBJ); } @@ -519,11 +511,7 @@ class DoliDBSqlite extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - //return $resultset->fetch(PDO::FETCH_ASSOC); - $ret = $resultset->fetchArray(SQLITE3_ASSOC); - if ($ret) { - return (array)$ret; - } + return $resultset->fetch(PDO::FETCH_ASSOC); } /** @@ -538,7 +526,7 @@ class DoliDBSqlite extends DoliDB if (! is_bool($resultset)) { if (! is_object($resultset)) { $resultset=$this->_results; } - return $resultset->fetchArray(SQLITE3_NUM); + return $resultset->fetch(PDO::FETCH_NUM); } else { @@ -559,9 +547,10 @@ class DoliDBSqlite extends DoliDB // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } if (preg_match("/^SELECT/i", $resultset->queryString)) { - return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q"); + $res = $this->db->query("SELECT count(*) FROM (" . $resultset->queryString . ") q"); + return $res->fetchColumn(); } - return 0; + return $resultset->rowCount(); } /** @@ -575,12 +564,9 @@ class DoliDBSqlite extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - if (preg_match("/^SELECT/i", $resultset->queryString)) { - return $this->num_rows($resultset); - } // mysql necessite un link de base pour cette fonction contrairement // a pqsql qui prend un resultset - return $this->db->changes(); + return $resultset->rowCount(); } @@ -595,7 +581,7 @@ class DoliDBSqlite extends DoliDB // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } // Si resultset en est un, on libere la memoire - if ($resultset && is_object($resultset)) $resultset->finalize(); + if (is_object($resultset)) $resultset->closeCursor(); } /** @@ -606,7 +592,12 @@ class DoliDBSqlite extends DoliDB */ function escape($stringtoencode) { - return Sqlite3::escapeString($stringtoencode); + $ret = $this->db->quote($stringtoencode); + $l = strlen($ret); + if ($l >= 2) { + return substr($ret, 1, $l -2); + } + return ''; } /** @@ -654,8 +645,8 @@ class DoliDBSqlite extends DoliDB { return $errorcode_map[$this->db->errorCode()]; }*/ - $errno=$this->db->lastErrorCode(); - if ($errno=='HY000' || $errno == 0) + $errno=$this->db->errorCode(); + if ($errno=='HY000') { if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS'; elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'; @@ -666,9 +657,6 @@ class DoliDBSqlite extends DoliDB if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; } - if ($errno > 1) { - // TODO Voir la liste des messages d'erreur - } return ($errno?'DB_ERROR_'.$errno:'0'); } @@ -699,7 +687,7 @@ class DoliDBSqlite extends DoliDB */ function last_insert_id($tab,$fieldid='rowid') { - return $this->db->lastInsertRowId(); + return $this->db->lastInsertId(); } /** @@ -1183,39 +1171,15 @@ class DoliDBSqlite extends DoliDB function getServerParametersValues($filter='') { $result=array(); - static $pragmas; - if (! isset($pragmas)) { - // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur - // indépendante de la base de données. - // cf. http://www.sqlite.org/pragma.html - $pragmas = array( - 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', - 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', - 'compile_options', 'data_version', /*'database_list',*/ - 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count', - 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check', - 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode', - 'max_page_count', 'page_count', 'page_size', 'parser_trace', - 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers', - 'reverse_unordered_selects', 'schema_version', 'user_version', - 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit', - 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', - 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', - 'wal_autocheckpoint', - ); - } - // TODO prendre en compte le filtre - foreach($pragmas as $var) { - $sql = "PRAGMA $var"; - $resql=$this->query($sql); - if ($resql) - { - $obj = $this->fetch_row($resql); - //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG); - $result[$var] = $obj[0]; - } - } + $sql='SHOW VARIABLES'; + if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; + $resql=$this->query($sql); + if ($resql) + { + while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; + } + return $result; } @@ -1228,7 +1192,7 @@ class DoliDBSqlite extends DoliDB function getServerStatusValues($filter='') { $result=array(); - /* + $sql='SHOW STATUS'; if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; $resql=$this->query($sql); @@ -1236,243 +1200,9 @@ class DoliDBSqlite extends DoliDB { while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; } - */ return $result; } - /** - * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees. - * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être - * statique et publique. Le nombre de parametres est determine automatiquement. - * @param string $name Le nom de la fonction a definir dans Sqlite - */ - private function addCustomFunction($name, $arg_count = -1) { - if ($this->db) { - $localname = __CLASS__ . '::' . 'db_' . $name; - $reflectClass = new ReflectionClass(__CLASS__); - $reflectFunction = $reflectClass->getMethod('db_' . $name); - if ($arg_count < 0) { - $arg_count = $reflectFunction->getNumberOfParameters(); - } - if (!$this->db->createFunction($name, $localname , $arg_count)) { - $this->error = "unable to create custom function '$name'"; - } - } - } - - /** - * Cette fonction est l'equivalent de la fonction MONTH de MySql. - * @param string $date - * @return integer - */ - public static function db_MONTH($date) { - return date('n', strtotime($date)); - } - - /** - * calcule du numéro de semaine - * - * @param string date - * @param int mode - */ - public static function db_WEEK($date, $mode = 0) { - $arr = date_parse($date); - $calc_year = 0; - return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year); - } - - public static function db_CURDATE() { - return date('Y-m-d'); - } - - public static function db_CURTIME() { - return date('H:i:s'); - } - - public static function db_WEEKDAY($date) { - $arr = date_parse($date); - return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0); - - } - - /** - * Cette fonction est l'equivelent de la fonction date_format de MySQL. - * @staticvar string $mysql_replacement Les symboles formatage a remplacer - * @param string $date la date dans un format ISO - * @param string $format la chaine de formatage - * @return string La date formatee. - */ - public static function db_date_format($date, $format) { - static $mysql_replacement; - if (! isset($mysql_replacement)) { - $mysql_replacement = array( - '%' => '%', - 'a' => 'D', - 'b' => 'M', - 'c' => 'n', - 'D' => 'jS', - 'd' => 'd', - 'e' => 'j', - 'f' => 'u', - 'H' => 'H', - 'h' => 'h', - 'I' => 'h', - 'i' => 'i', - 'k' => 'H', - 'l' => 'g', - 'M' => 'F', - 'm' => 'm', - 'p' => 'A', - 'r' => 'h:i:s A', - 'S' => 's', - 's' => 's', - 'T' => 'H:i:s', - 'W' => 'l', - 'w' => 'w', - 'Y' => 'Y', - 'y' => 'y', - ); - } - - $fmt = ''; - $lg = strlen($format); - $state = 0; - $timestamp = strtotime($date); - $yday = date('z', $timestamp); - $month = (integer)date("n", $timestamp); - $year = (integer)date("Y", $timestamp); - $day = (integer)date("d", $timestamp); - for($idx = 0; $idx < $lg; ++$idx) { - $char = $format[$idx]; - if ($state == 0) { - if ($char == '%') { - $state = 1; - } else { - $fmt .= $char; - } - } - elseif ($state == 1) { - if (array_key_exists($char, $mysql_replacement)) { - $fmt .= $mysql_replacement[$char]; - } else { - $calc_year = 0; - switch ($char) { - case 'j': // day of the year 001 - $char = sprintf("%03d", $yday+1); - break; - case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year)); - break; - case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); - break; - case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); - break; - case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi - $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); - break; - case 'X': - self::calc_week($year, $month, $day, 6, $calc_year); - $char = sprintf("%04d", $calc_year); - break; - case 'x': - self::calc_week($year, $month, $day, 3, $calc_year); - $char = sprintf("%04d", $calc_year); - break; - } - $fmt .= $char; - } - $state = 0; - } - } - return date($fmt, strtotime($date)); - } - - /** - * Equivalent de la fonction MySQL IF - * @param boolean $test Le resultat du test - * @param mixed $true_part Partie a retourner si vrai - * @param mixed $false_part Partie a retourner si faux - * @return mixed Partie selectionnee en fonction du test - */ - public static function db_IF($test, $true_part, $false_part) { - return ( $test ) ? $true_part : $false_part; - } - - // Adapté de mytime.c des sources de mariadb - // fonction calc_daynr - private static function calc_daynr($year, $month, $day) { - $y = $year; - if ($y == 0 && $month == 0) return 0; - $num = (365* $y + 31 * ($month - 1) + $day); - if ($month <= 2) { - $y--; } - else { - $num -= floor(($month * 4 + 23) / 10); - } - $temp = floor(($y / 100 + 1) * 3 / 4); - return $num + floor($y / 4) - $temp; - } - - private static function calc_weekday($daynr, $sunday_first_day_of_week) { - $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7); - return $ret; - } - - private static function calc_days_in_year($year) - { - return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365); - } - - private static function week_mode($mode) { - $week_format= ($mode & 7); - if (!($week_format & self::WEEK_MONDAY_FIRST)) { - $week_format^= self::WEEK_FIRST_WEEKDAY; - } - return $week_format; - } - - - private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) { - $daynr=self::calc_daynr($year,$month,$day); - $first_daynr=self::calc_daynr($year,1,1); - $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0; - $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0; - $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0; - - $weekday=self::calc_weekday($first_daynr, !$monday_first); - $calc_year=$year; - - if ($month == 1 && $day <= 7-$weekday) - { - if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) - return 0; - $week_year= 1; - $calc_year--; - $first_daynr-= ($days=self::calc_days_in_year($calc_year)); - $weekday= ($weekday + 53*7- $days) % 7; - } - - if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) { - $days= $daynr - ($first_daynr+ (7-$weekday)); - } - else { - $days= $daynr - ($first_daynr - $weekday); - } - - if ($week_year && $days >= 52*7) - { - $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7; - if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) - { - $calc_year++; - return 1; - } - } - return floor($days/7+1); - } - } diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php new file mode 100644 index 00000000000..f232acb199e --- /dev/null +++ b/htdocs/core/db/sqlite3.class.php @@ -0,0 +1,1478 @@ + + * Copyright (C) 2002-2005 Rodolphe Quiedeville + * Copyright (C) 2004-2011 Laurent Destailleur + * Copyright (C) 2006 Andre Cianfarani + * Copyright (C) 2005-2009 Regis Houssin + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (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 + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/db/sqlite.class.php + * \brief Class file to manage Dolibarr database access for a Sqlite database + */ + +require_once DOL_DOCUMENT_ROOT .'/core/db/DoliDB.class.php'; + +/** + * Class to manage Dolibarr database access for a Sqlite database + */ +class DoliDBSqlite3 extends DoliDB +{ + //! Database type + public $type='sqlite3'; + //! Database label + const LABEL='Sqlite3'; + //! Version min database + const VERSIONMIN='3.0.0'; + //! Resultset of last query + private $_results; + + const WEEK_MONDAY_FIRST=1; + const WEEK_YEAR = 2; + const WEEK_FIRST_WEEKDAY=4; + + + /** + * 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 + */ + function __construct($type, $host, $user, $pass, $name='', $port=0) + { + global $conf,$langs; + + // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static + 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; + + $this->database_user=$user; + $this->database_host=$host; + $this->database_port=$port; + + $this->transaction_opened=0; + + //print "Name DB: $host,$user,$pass,$name
"; + + /*if (! function_exists("sqlite_query")) + { + $this->connected = 0; + $this->ok = 0; + $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver."; + dol_syslog(get_class($this)."::DoliDBSqlite3 : Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.",LOG_ERR); + return $this->ok; + }*/ + + /*if (! $host) + { + $this->connected = 0; + $this->ok = 0; + $this->error=$langs->trans("ErrorWrongHostParameter"); + dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR); + return $this->ok; + }*/ + + // Essai connexion serveur + // We do not try to connect to database, only to server. Connect to database is done later in constrcutor + $this->db = $this->connect($host, $user, $pass, $name, $port); + + if ($this->db) + { + $this->connected = 1; + $this->ok = 1; + $this->database_selected = 1; + $this->database_name = $name; + + $this->addCustomFunction('IF'); + $this->addCustomFunction('MONTH'); + $this->addCustomFunction('CURTIME'); + $this->addCustomFunction('CURDATE'); + $this->addCustomFunction('WEEK', 1); + $this->addCustomFunction('WEEK', 2); + $this->addCustomFunction('WEEKDAY'); + $this->addCustomFunction('date_format'); + //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } + else + { + // host, login ou password incorrect + $this->connected = 0; + $this->ok = 0; + $this->database_selected = 0; + $this->database_name = ''; + //$this->error=sqlite_connect_error(); + dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error,LOG_ERR); + } + + return $this->ok; + } + + + /** + * 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...) + * @return string SQL request line converted + */ + static function convertSQLFromMysql($line,$type='ddl') + { + // Removed empty line if this is a comment line for SVN tagging + if (preg_match('/^--\s\$Id/i',$line)) { + return ''; + } + // Return line if this is a comment + if (preg_match('/^#/i',$line) || preg_match('/^$/i',$line) || preg_match('/^--/i',$line)) + { + return $line; + } + if ($line != "") + { + if ($type == 'auto') + { + if (preg_match('/ALTER TABLE/i',$line)) $type='dml'; + else if (preg_match('/CREATE TABLE/i',$line)) $type='dml'; + else if (preg_match('/DROP TABLE/i',$line)) $type='dml'; + } + + if ($type == 'dml') + { + $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 integer PRIMARY KEY AUTOINCREMENT',$line); + //$line = "-- ".$line." replaced by --\n".$newline; + $line=$newline; + } + + // tinyint type conversion + $line=str_replace('tinyint','smallint',$line); + + // nuke unsigned + $line=preg_replace('/(int\w+|smallint)\s+unsigned/i','\\1',$line); + + // 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); + + // 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); + + // unique index(field1,field2) + if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i',$line)) + { + $line=preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i','UNIQUE\(\\1\)',$line); + } + + // We remove end of requests "AFTER fieldxxx" + $line=preg_replace('/AFTER [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_]+ DROP INDEX/i','DROP INDEX',$line); + + // Translate order to rename fields + if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i',$line,$reg)) + { + $line = "-- ".$line." replaced by --\n"; + $line.= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3]; + } + + // Translate order to modify field format + if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i',$line,$reg)) + { + $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 create a unique index instead as dynamic creation of primary key is not supported + // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity); + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i',$line,$reg)) + { + $line = "-- ".$line." replaced by --\n"; + $line.= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3]; + } + + // Translate order to drop foreign keys + // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx; + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i',$line,$reg)) + { + $line = "-- ".$line." replaced by --\n"; + $line.= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2]; + } + + // alter table add [unique] [index] (field1, field2 ...) + // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version) + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i',$line,$reg)) + { + $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.")"; + } + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$line, $reg)) { + // Pour l'instant les contraintes ne sont pas créées + dol_syslog(get_class().'::query line emptied'); + $line = 'SELECT 0;'; + + } + + //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) { + //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line); + //} + } + + // Delete using criteria on other table must not declare twice the deleted table + // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable + 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 + { + $line=preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i','DELETE FROM \\1 USING \\3', $line); + } + } + + // Remove () in the tables in FROM if one table + $line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line); + //print $line."\n"; + + // Remove () in the tables in FROM if two table + $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); + //print $line."\n"; + + // Remove () in the tables in FROM if two table + $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); + //print $line."\n"; + + //print "type=".$type." newline=".$line."
\n"; + } + + return $line; + } + + /** + * Select a database + * + * @param string $database Name of database + * @return boolean true if OK, false if KO + */ + function select_db($database) + { + dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG); + return sqlite_select_db($this->db,$database); + } + + + /** + * Connexion to server + * + * @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) + * @param string $port Port of database server + * @return resource Database access handler + * @see close + */ + function connect($host, $login, $passwd, $name, $port=0) + { + global $conf,$main_data_dir; + + dol_syslog(get_class($this)."::connect name=".$name,LOG_DEBUG); + + $dir=$main_data_dir; + if (empty($dir)) $dir=DOL_DATA_ROOT; + // With sqlite, port must be in connect parameters + //if (! $newport) $newport=3306; + $database_name = $dir.'/database_'.$name.'.sdb'; + try { + /*** connect to SQLite database ***/ + //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); + $this->db = new SQLite3($database_name); + //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + } + catch(Exception $e) + { + $this->error= self::LABEL.' '.$e->getMessage().' current dir='.$database_name; + return ''; + } + + //print "Resultat fonction connect: ".$this->db; + return $this->db; + } + + + /** + * Return version of database server + * + * @return string Version string + */ + function getVersion() + { + return $this->db->version()['versionString']; + } + + /** + * Return version of database client driver + * + * @return string Version string + */ + function getDriverInfo() + { + // FIXME: Dummy method + // TODO: Implement + + return ''; + } + + + /** + * Close database connexion + * + * @return boolean True if disconnect successfull, false otherwise + * @see connect + */ + function close() + { + 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); + $this->connected=0; + $this->db->close(); + $this->db=null; // Clean this->db + return true; + } + return false; + } + + /** + * Execute a SQL request and return the resultset + * + * @param string $query SQL query string + * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions). + * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. + * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) + * @return resource Resultset of answer + */ + function query($query,$usesavepoint=0,$type='auto') + { + $errmsg=''; + + $ret=''; + $query = trim($query); + $this->error = 0; + + // Convert MySQL syntax to SQLite syntax + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$query, $reg)) { + // Ajout d'une clef étrangère à la table + // procédure de remplacement de la table pour ajouter la contrainte + // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid) + // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)) + $foreignFields = $reg[5]; + $foreignTable = $reg[4]; + $localfields = $reg[3]; + $constraintname=trim($reg[2]); + $tablename=trim($reg[1]); + + $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); + + // 1- Renommer la table avec un nom temporaire + $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); + + // 2- Recréer la table avec la contrainte ajoutée + + // on bricole la requete pour ajouter la contrainte + $descTable = substr($descTable, 0, strlen($descTable) - 1); + $descTable .= ", CONSTRAINT " . $constraintname . " FOREIGN KEY (" . $localfields . ") REFERENCES " .$foreignTable . "(" . $foreignFields . ")"; + + // fermeture de l'instruction + $descTable .= ')'; + + // Création proprement dite de la table + $this->query($descTable); + + // 3- Transférer les données + $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); + + // 4- Supprimer la table temporaire + $this->query('DROP TABLE tmp_' . $tablename); + + // dummy statement + $query="SELECT 0"; + + } else { + $query=$this->convertSQLFromMysql($query,$type); + } + //print "After convertSQLFromMysql:\n".$query."
\n"; + + dol_syslog('sql='.$query, LOG_DEBUG); + + // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE) + try { + //$ret = $this->db->exec($query); + $ret = $this->db->query($query); // $ret is a PDO object + if ($ret) { + $ret->queryString = $query; + } + } + catch(Exception $e) + { + $this->error=$this->db->lastErrorMsg(); + } + + if (! preg_match("/^COMMIT/i",$query) && ! preg_match("/^ROLLBACK/i",$query)) + { + // Si requete utilisateur, on la sauvegarde ainsi que son resultset + if (! is_object($ret) || $this->error) + { + $this->lastqueryerror = $query; + $this->lasterror = $this->error(); + $this->lasterrno = $this->errno(); + + dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); + + $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror; + + if (preg_match('/[0-9]/',$this->lasterrno)) { + $errormsg .= ' ('.$this->lasterrno.')'; + } + + dol_syslog($errormsg, LOG_ERR); + } + $this->lastquery=$query; + $this->_results = $ret; + } + + return $ret; + } + + /** + * Renvoie la ligne courante (comme un objet) pour le curseur resultset + * + * @param Resultset $resultset Curseur de la requete voulue + * @return Object Object result line or false if KO or end of cursor + */ + function fetch_object($resultset) + { + // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion + if (! is_object($resultset)) { $resultset=$this->_results; } + //return $resultset->fetch(PDO::FETCH_OBJ); + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (object)$ret; + } + } + + + /** + * Return datas as an array + * + * @param Resultset $resultset Resultset of request + * @return array Array + */ + function fetch_array($resultset) + { + // If resultset not provided, we take the last used by connexion + if (! is_object($resultset)) { $resultset=$this->_results; } + //return $resultset->fetch(PDO::FETCH_ASSOC); + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (array)$ret; + } + } + + /** + * Return datas as an array + * + * @param Resultset $resultset Resultset of request + * @return array Array + */ + function fetch_row($resultset) + { + // If resultset not provided, we take the last used by connexion + if (! is_bool($resultset)) + { + if (! is_object($resultset)) { $resultset=$this->_results; } + return $resultset->fetchArray(SQLITE3_NUM); + } + else + { + // si le curseur est un booleen on retourne la valeur 0 + return 0; + } + } + + /** + * Return number of lines for result of a SELECT + * + * @param Resultset $resultset Resulset of requests + * @return int Nb of lines + * @see affected_rows + */ + function num_rows($resultset) + { + // If resultset not provided, we take the last used by connexion + if (! is_object($resultset)) { $resultset=$this->_results; } + if (preg_match("/^SELECT/i", $resultset->queryString)) { + return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q"); + } + return 0; + } + + /** + * Return number of lines for result of a SELECT + * + * @param Resultset $resultset Resulset of requests + * @return int Nb of lines + * @see affected_rows + */ + function affected_rows($resultset) + { + // If resultset not provided, we take the last used by connexion + if (! is_object($resultset)) { $resultset=$this->_results; } + if (preg_match("/^SELECT/i", $resultset->queryString)) { + return $this->num_rows($resultset); + } + // mysql necessite un link de base pour cette fonction contrairement + // a pqsql qui prend un resultset + return $this->db->changes(); + } + + + /** + * Free last resultset used. + * + * @param resultset $resultset Curseur de la requete voulue + * @return void + */ + function free($resultset=0) + { + // If resultset not provided, we take the last used by connexion + if (! is_object($resultset)) { $resultset=$this->_results; } + // Si resultset en est un, on libere la memoire + if ($resultset && is_object($resultset)) $resultset->finalize(); + } + + /** + * Escape a string to insert data + * + * @param string $stringtoencode String to escape + * @return string String escaped + */ + function escape($stringtoencode) + { + return Sqlite3::escapeString($stringtoencode); + } + + /** + * Renvoie le code erreur generique de l'operation precedente. + * + * @return string Error code (Exemples: DB_ERROR_TABLE_ALREADY_EXISTS, DB_ERROR_RECORD_ALREADY_EXISTS...) + */ + function errno() + { + if (! $this->connected) { + // Si il y a eu echec de connexion, $this->db n'est pas valide. + return 'DB_ERROR_FAILED_TO_CONNECT'; + } + else { + // Constants to convert error code to a generic Dolibarr error code + /*$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', + 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS', + 1051 => 'DB_ERROR_NOSUCHTABLE', + 1054 => 'DB_ERROR_NOSUCHFIELD', + 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS', + 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS', + 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS', + 1064 => 'DB_ERROR_SYNTAX', + 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS', + 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY', + 1091 => 'DB_ERROR_NOSUCHFIELD', + 1100 => 'DB_ERROR_NOT_LOCKED', + 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW', + 1146 => 'DB_ERROR_NOSUCHTABLE', + 1216 => 'DB_ERROR_NO_PARENT', + 1217 => 'DB_ERROR_CHILD_EXISTS', + 1451 => 'DB_ERROR_CHILD_EXISTS' + ); + + if (isset($errorcode_map[$this->db->errorCode()])) + { + return $errorcode_map[$this->db->errorCode()]; + }*/ + $errno=$this->db->lastErrorCode(); + if ($errno=='HY000' || $errno == 0) + { + if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS'; + elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'; + elseif (preg_match('/syntax error/i',$this->error)) return 'DB_ERROR_SYNTAX'; + } + if ($errno=='23000') + { + if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; + elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; + } + if ($errno > 1) { + // TODO Voir la liste des messages d'erreur + } + + return ($errno?'DB_ERROR_'.$errno:'0'); + } + } + + /** + * Renvoie le texte de l'erreur mysql de l'operation precedente. + * + * @return string Error text + */ + function error() + { + if (! $this->connected) { + // Si il y a eu echec de connexion, $this->db n'est pas valide pour sqlite_error. + return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version'; + } + else { + return $this->error; + } + } + + /** + * Get last ID after an insert INSERT + * + * @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql + * @param string $fieldid Field name + * @return int Id of row + */ + function last_insert_id($tab,$fieldid='rowid') + { + return $this->db->lastInsertRowId(); + } + + /** + * 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 return XXX(field) or XXX('value') or field or 'value' + */ + function encrypt($fieldorvalue, $withQuotes=0) + { + global $conf; + + // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption) + $cryptType = ($conf->db->dolibarr_main_db_encryption?$conf->db->dolibarr_main_db_encryption:0); + + //Encryption key + $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:''); + + $return = ($withQuotes?"'":"").$this->escape($fieldorvalue).($withQuotes?"'":""); + + if ($cryptType && !empty($cryptKey)) + { + if ($cryptType == 2) + { + $return = 'AES_ENCRYPT('.$return.',\''.$cryptKey.'\')'; + } + else if ($cryptType == 1) + { + $return = 'DES_ENCRYPT('.$return.',\''.$cryptKey.'\')'; + } + } + + return $return; + } + + /** + * Decrypt sensitive data in database + * + * @param string $value Value to decrypt + * @return string Decrypted value if used + */ + function decrypt($value) + { + global $conf; + + // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption) + $cryptType = ($conf->db->dolibarr_main_db_encryption?$conf->db->dolibarr_main_db_encryption:0); + + //Encryption key + $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey)?$conf->db->dolibarr_main_db_cryptkey:''); + + $return = $value; + + if ($cryptType && !empty($cryptKey)) + { + if ($cryptType == 2) + { + $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')'; + } + else if ($cryptType == 1) + { + $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')'; + } + } + + return $return; + } + + + /** + * Return connexion ID + * + * @return string Id connexion + */ + function DDLGetConnectId() + { + return '?'; + } + + + /** + * Create a new database + * 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 + * + * @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 + * @return resource resource defined if OK, null if KO + */ + function DDLCreateDb($database,$charset='',$collation='',$owner='') + { + if (empty($charset)) $charset=$this->forcecharset; + if (empty($collation)) $collation=$this->forcecollate; + + // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci + $sql = 'CREATE DATABASE '.$database; + $sql.= ' DEFAULT CHARACTER SET '.$charset.' DEFAULT COLLATE '.$collation; + + dol_syslog($sql,LOG_DEBUG); + $ret=$this->query($sql); + if (! $ret) + { + // We try again for compatibility with Mysql < 4.1.1 + $sql = 'CREATE DATABASE '.$database; + $ret=$this->query($sql); + dol_syslog($sql,LOG_DEBUG); + } + return $ret; + } + + /** + * List tables into a database + * + * @param string $database Name of database + * @param string $table Name of table filter ('xxx%') + * @return array List of tables in an array + */ + function DDLListTables($database, $table='') + { + $listtables=array(); + + $like = ''; + if ($table) $like = "LIKE '".$table."'"; + $sql="SHOW TABLES FROM ".$database." ".$like.";"; + //print $sql; + $result = $this->query($sql); + while($row = $this->fetch_row($result)) + { + $listtables[] = $row[0]; + } + return $listtables; + } + + /** + * List information of columns into a table. + * + * @param string $table Name of table + * @return array Tableau des informations des champs de la table + * TODO modify for sqlite + */ + function DDLInfoTable($table) + { + $infotables=array(); + + $sql="SHOW FULL COLUMNS FROM ".$table.";"; + + dol_syslog($sql,LOG_DEBUG); + $result = $this->query($sql); + while($row = $this->fetch_row($result)) + { + $infotables[] = $row; + } + return $infotables; + } + + /** + * Create a table into database + * + * @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 + * @param string $keys Tableau des champs cles noms => valeur + * @return int <0 if KO, >=0 if OK + */ + function DDLCreateTable($table,$fields,$primary_key,$type,$unique_keys="",$fulltext_keys="",$keys="") + { + // 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."("; + $i=0; + foreach($fields as $field_name => $field_desc) + { + $sqlfields[$i] = $field_name." "; + $sqlfields[$i] .= $field_desc['type']; + if( preg_match("/^[^\s]/i",$field_desc['value'])) + $sqlfields[$i] .= "(".$field_desc['value'].")"; + else if( preg_match("/^[^\s]/i",$field_desc['attribute'])) + $sqlfields[$i] .= " ".$field_desc['attribute']; + else if( preg_match("/^[^\s]/i",$field_desc['default'])) + { + if(preg_match("/null/i",$field_desc['default'])) + $sqlfields[$i] .= " default ".$field_desc['default']; + else + $sqlfields[$i] .= " default '".$field_desc['default']."'"; + } + else if( preg_match("/^[^\s]/i",$field_desc['null'])) + $sqlfields[$i] .= " ".$field_desc['null']; + + else if( preg_match("/^[^\s]/i",$field_desc['extra'])) + $sqlfields[$i] .= " ".$field_desc['extra']; + $i++; + } + if($primary_key != "") + $pk = "primary key(".$primary_key.")"; + + if($unique_keys != "") + { + $i = 0; + foreach($unique_keys as $key => $value) + { + $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$value."')"; + $i++; + } + } + if($keys != "") + { + $i = 0; + foreach($keys as $key => $value) + { + $sqlk[$i] = "KEY ".$key." (".$value.")"; + $i++; + } + } + $sql .= implode(',',$sqlfields); + if($primary_key != "") + $sql .= ",".$pk; + if($unique_keys != "") + $sql .= ",".implode(',',$sqluq); + if($keys != "") + $sql .= ",".implode(',',$sqlk); + $sql .=") type=".$type; + + dol_syslog($sql,LOG_DEBUG); + if(! $this -> query($sql)) + return -1; + else + return 1; + } + + /** + * Return a pointer of line with description of a table or field + * + * @param string $table Name of table + * @param string $field Optionnel : Name of field if we want description of field + * @return resource Resource + */ + function DDLDescTable($table,$field="") + { + $sql="DESC ".$table." ".$field; + + dol_syslog(get_class($this)."::DDLDescTable ".$sql,LOG_DEBUG); + $this->_results = $this->query($sql); + return $this->_results; + } + + /** + * Create a new field into table + * + * @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 + */ + function DDLAddField($table,$field_name,$field_desc,$field_position="") + { + // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra + // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment'); + $sql= "ALTER TABLE ".$table." ADD ".$field_name." "; + $sql.= $field_desc['type']; + if(preg_match("/^[^\s]/i",$field_desc['value'])) + if (! in_array($field_desc['type'],array('date','datetime'))) + { + $sql.= "(".$field_desc['value'].")"; + } + if(preg_match("/^[^\s]/i",$field_desc['attribute'])) + $sql.= " ".$field_desc['attribute']; + if(preg_match("/^[^\s]/i",$field_desc['null'])) + $sql.= " ".$field_desc['null']; + if(preg_match("/^[^\s]/i",$field_desc['default'])) + { + if(preg_match("/null/i",$field_desc['default'])) + $sql.= " default ".$field_desc['default']; + else + $sql.= " default '".$field_desc['default']."'"; + } + if(preg_match("/^[^\s]/i",$field_desc['extra'])) + $sql.= " ".$field_desc['extra']; + $sql.= " ".$field_position; + + dol_syslog(get_class($this)."::DDLAddField ".$sql,LOG_DEBUG); + if(! $this->query($sql)) + { + return -1; + } + else + { + return 1; + } + } + + /** + * Update format of a field into a table + * + * @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 + */ + function DDLUpdateField($table,$field_name,$field_desc) + { + $sql = "ALTER TABLE ".$table; + $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; + if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') { + $sql.="(".$field_desc['value'].")"; + } + + dol_syslog(get_class($this)."::DDLUpdateField ".$sql,LOG_DEBUG); + if (! $this->query($sql)) + return -1; + else + return 1; + } + + /** + * Drop a field from table + * + * @param string $table Name of table + * @param string $field_name Name of field to drop + * @return int <0 if KO, >0 if OK + */ + function DDLDropField($table,$field_name) + { + $sql= "ALTER TABLE ".$table." DROP COLUMN `".$field_name."`"; + dol_syslog(get_class($this)."::DDLDropField ".$sql,LOG_DEBUG); + if (! $this->query($sql)) + { + $this->error=$this->lasterror(); + return -1; + } + else return 1; + } + + + /** + * Create a user and privileges to connect to database (even if database does not exists yet) + * + * @param string $dolibarr_main_db_host Ip serveur + * @param string $dolibarr_main_db_user Nom user a creer + * @param string $dolibarr_main_db_pass Mot de passe user a creer + * @param string $dolibarr_main_db_name Database name where user must be granted + * @return int <0 if KO, >=0 if OK + */ + function DDLCreateUser($dolibarr_main_db_host,$dolibarr_main_db_user,$dolibarr_main_db_pass,$dolibarr_main_db_name) + { + $sql = "INSERT INTO user "; + $sql.= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)"; + $sql.= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')"; + $sql.= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')"; + + dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log + $resql=$this->query($sql); + if (! $resql) + { + return -1; + } + + $sql = "INSERT INTO db "; + $sql.= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)"; + $sql.= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'"; + $sql.= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')"; + + dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); + $resql=$this->query($sql); + if (! $resql) + { + return -1; + } + + $sql="FLUSH Privileges"; + + dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); + $resql=$this->query($sql); + if (! $resql) + { + return -1; + } + + return 1; + } + + /** + * Return charset used to store data in database + * + * @return string Charset + */ + function getDefaultCharacterSetDatabase() + { + return 'UTF-8'; + } + + /** + * Return list of available charset that can be used to store data in database + * + * @return array List of Charset + */ + function getListOfCharacterSet() + { + $liste = array(); + $i=0; + $liste[$i]['charset'] = 'UTF-8'; + $liste[$i]['description'] = 'UTF-8'; + return $liste; + } + + /** + * Return collation used in database + * + * @return string Collation value + */ + function getDefaultCollationDatabase() + { + return 'UTF-8'; + } + + /** + * Return list of available collation that can be used for database + * + * @return array List of Collation + */ + function getListOfCollation() + { + $liste = array(); + $i=0; + $liste[$i]['charset'] = 'UTF-8'; + $liste[$i]['description'] = 'UTF-8'; + return $liste; + } + + /** + * Return full path of dump program + * + * @return string Full path of dump program + */ + function getPathOfDump() + { + $fullpathofdump='/pathtomysqldump/mysqldump'; + + $resql=$this->query('SHOW VARIABLES LIKE \'basedir\''); + if ($resql) + { + $liste=$this->fetch_array($resql); + $basedir=$liste['Value']; + $fullpathofdump=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysqldump'; + } + return $fullpathofdump; + } + + /** + * Return full path of restore program + * + * @return string Full path of restore program + */ + function getPathOfRestore() + { + $fullpathofimport='/pathtomysql/mysql'; + + $resql=$this->query('SHOW VARIABLES LIKE \'basedir\''); + if ($resql) + { + $liste=$this->fetch_array($resql); + $basedir=$liste['Value']; + $fullpathofimport=$basedir.(preg_match('/\/$/',$basedir)?'':'/').'bin/mysql'; + } + return $fullpathofimport; + } + + /** + * Return value of server parameters + * + * @param string $filter Filter list on a particular value + * @return array Array of key-values (key=>value) + */ + function getServerParametersValues($filter='') + { + $result=array(); + static $pragmas; + if (! isset($pragmas)) { + // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur + // indépendante de la base de données. + // cf. http://www.sqlite.org/pragma.html + $pragmas = array( + 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', + 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', + 'compile_options', 'data_version', /*'database_list',*/ + 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count', + 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check', + 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode', + 'max_page_count', 'page_count', 'page_size', 'parser_trace', + 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers', + 'reverse_unordered_selects', 'schema_version', 'user_version', + 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit', + 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', + 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', + 'wal_autocheckpoint', + ); + } + + // TODO prendre en compte le filtre + foreach($pragmas as $var) { + $sql = "PRAGMA $var"; + $resql=$this->query($sql); + if ($resql) + { + $obj = $this->fetch_row($resql); + //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG); + $result[$var] = $obj[0]; + } + } + return $result; + } + + /** + * Return value of server status + * + * @param string $filter Filter list on a particular value + * @return array Array of key-values (key=>value) + */ + function getServerStatusValues($filter='') + { + $result=array(); + /* + $sql='SHOW STATUS'; + if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; + $resql=$this->query($sql); + if ($resql) + { + while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; + } + */ + + return $result; + } + + /** + * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees. + * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être + * statique et publique. Le nombre de parametres est determine automatiquement. + * @param string $name Le nom de la fonction a definir dans Sqlite + */ + private function addCustomFunction($name, $arg_count = -1) { + if ($this->db) { + $localname = __CLASS__ . '::' . 'db_' . $name; + $reflectClass = new ReflectionClass(__CLASS__); + $reflectFunction = $reflectClass->getMethod('db_' . $name); + if ($arg_count < 0) { + $arg_count = $reflectFunction->getNumberOfParameters(); + } + if (!$this->db->createFunction($name, $localname , $arg_count)) { + $this->error = "unable to create custom function '$name'"; + } + } + } + + /** + * Cette fonction est l'equivalent de la fonction MONTH de MySql. + * @param string $date + * @return integer + */ + public static function db_MONTH($date) { + return date('n', strtotime($date)); + } + + /** + * calcule du numéro de semaine + * + * @param string date + * @param int mode + */ + public static function db_WEEK($date, $mode = 0) { + $arr = date_parse($date); + $calc_year = 0; + return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year); + } + + public static function db_CURDATE() { + return date('Y-m-d'); + } + + public static function db_CURTIME() { + return date('H:i:s'); + } + + public static function db_WEEKDAY($date) { + $arr = date_parse($date); + return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0); + + } + + /** + * Cette fonction est l'equivelent de la fonction date_format de MySQL. + * @staticvar string $mysql_replacement Les symboles formatage a remplacer + * @param string $date la date dans un format ISO + * @param string $format la chaine de formatage + * @return string La date formatee. + */ + public static function db_date_format($date, $format) { + static $mysql_replacement; + if (! isset($mysql_replacement)) { + $mysql_replacement = array( + '%' => '%', + 'a' => 'D', + 'b' => 'M', + 'c' => 'n', + 'D' => 'jS', + 'd' => 'd', + 'e' => 'j', + 'f' => 'u', + 'H' => 'H', + 'h' => 'h', + 'I' => 'h', + 'i' => 'i', + 'k' => 'H', + 'l' => 'g', + 'M' => 'F', + 'm' => 'm', + 'p' => 'A', + 'r' => 'h:i:s A', + 'S' => 's', + 's' => 's', + 'T' => 'H:i:s', + 'W' => 'l', + 'w' => 'w', + 'Y' => 'Y', + 'y' => 'y', + ); + } + + $fmt = ''; + $lg = strlen($format); + $state = 0; + $timestamp = strtotime($date); + $yday = date('z', $timestamp); + $month = (integer)date("n", $timestamp); + $year = (integer)date("Y", $timestamp); + $day = (integer)date("d", $timestamp); + for($idx = 0; $idx < $lg; ++$idx) { + $char = $format[$idx]; + if ($state == 0) { + if ($char == '%') { + $state = 1; + } else { + $fmt .= $char; + } + } + elseif ($state == 1) { + if (array_key_exists($char, $mysql_replacement)) { + $fmt .= $mysql_replacement[$char]; + } else { + $calc_year = 0; + switch ($char) { + case 'j': // day of the year 001 + $char = sprintf("%03d", $yday+1); + break; + case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year)); + break; + case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); + break; + case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); + break; + case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi + $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); + break; + case 'X': + self::calc_week($year, $month, $day, 6, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + case 'x': + self::calc_week($year, $month, $day, 3, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + } + $fmt .= $char; + } + $state = 0; + } + } + return date($fmt, strtotime($date)); + } + + /** + * Equivalent de la fonction MySQL IF + * @param boolean $test Le resultat du test + * @param mixed $true_part Partie a retourner si vrai + * @param mixed $false_part Partie a retourner si faux + * @return mixed Partie selectionnee en fonction du test + */ + public static function db_IF($test, $true_part, $false_part) { + return ( $test ) ? $true_part : $false_part; + } + + // Adapté de mytime.c des sources de mariadb + // fonction calc_daynr + private static function calc_daynr($year, $month, $day) { + $y = $year; + if ($y == 0 && $month == 0) return 0; + $num = (365* $y + 31 * ($month - 1) + $day); + if ($month <= 2) { + $y--; } + else { + $num -= floor(($month * 4 + 23) / 10); + } + $temp = floor(($y / 100 + 1) * 3 / 4); + return $num + floor($y / 4) - $temp; + } + + private static function calc_weekday($daynr, $sunday_first_day_of_week) { + $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7); + return $ret; + } + + private static function calc_days_in_year($year) + { + return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365); + } + + private static function week_mode($mode) { + $week_format= ($mode & 7); + if (!($week_format & self::WEEK_MONDAY_FIRST)) { + $week_format^= self::WEEK_FIRST_WEEKDAY; + } + return $week_format; + } + + + private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) { + $daynr=self::calc_daynr($year,$month,$day); + $first_daynr=self::calc_daynr($year,1,1); + $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0; + $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0; + $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0; + + $weekday=self::calc_weekday($first_daynr, !$monday_first); + $calc_year=$year; + + if ($month == 1 && $day <= 7-$weekday) + { + if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) + return 0; + $week_year= 1; + $calc_year--; + $first_daynr-= ($days=self::calc_days_in_year($calc_year)); + $weekday= ($weekday + 53*7- $days) % 7; + } + + if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) { + $days= $daynr - ($first_daynr+ (7-$weekday)); + } + else { + $days= $daynr - ($first_daynr - $weekday); + } + + if ($week_year && $days >= 52*7) + { + $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7; + if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) + { + $calc_year++; + return 1; + } + } + return floor($days/7+1); + } + +} + diff --git a/htdocs/install/etape2.php b/htdocs/install/etape2.php index d934f79f0af..612c3c64148 100644 --- a/htdocs/install/etape2.php +++ b/htdocs/install/etape2.php @@ -51,7 +51,7 @@ if ($dolibarr_main_db_type == "mysql") $choix=1; if ($dolibarr_main_db_type == "mysqli") $choix=1; if ($dolibarr_main_db_type == "pgsql") $choix=2; if ($dolibarr_main_db_type == "mssql") $choix=3; -if ($dolibarr_main_db_type == "sqlite") $choix=4; +if ($dolibarr_main_db_type == "sqlite3") $choix=4; //if (empty($choix)) dol_print_error('','Database type '.$dolibarr_main_db_type.' not supported into etape2.php page'); @@ -413,7 +413,7 @@ if ($action == "set") if ($choix==1) $dir = "mysql/functions/"; elseif ($choix==2) $dir = "pgsql/functions/"; elseif ($choix==3) $dir = "mssql/functions/"; - elseif ($choix==4) { $dir = "sqlite/functions/"; } + elseif ($choix==4) { $dir = "sqlite3/functions/"; } // Creation donnees $file = "functions.sql"; diff --git a/htdocs/install/fileconf.php b/htdocs/install/fileconf.php index 49b80eb1b6b..ec3e208374b 100644 --- a/htdocs/install/fileconf.php +++ b/htdocs/install/fileconf.php @@ -306,7 +306,7 @@ if (! empty($force_install_message)) $class='DoliDB'.ucfirst($type); include_once $dir."/".$file; - //if ($type == 'sqlite') continue; // We hide sqlite because support can't be complete unti sqlit does not manage foreign key creation after table creation + if ($type == 'sqlite') continue; // We hide sqlite because support can't be complete unti sqlit does not manage foreign key creation after table creation // Version min of database $versionbasemin=explode('.',$class::VERSIONMIN); @@ -320,7 +320,7 @@ if (! empty($force_install_message)) if ($type=='mysqli') { $testfunction='mysqli_connect'; $testclass=''; } if ($type=='pgsql') { $testfunction='pg_connect'; $testclass=''; } if ($type=='mssql') { $testfunction='mssql_connect'; $testclass=''; } - if ($type=='sqlite') { $testfunction=''; $testclass='PDO'; } + if ($type=='sqlite3') { $testfunction=''; $testclass='SQLite3'; } $option.=''; @@ -479,7 +480,7 @@ if (! empty($force_install_message)) jQuery(document).ready(function() { jQuery("#db_type").change(function() { - if (jQuery("#db_type").val()=='sqlite') { jQuery(".hidesqlite").hide(); } + if (jQuery("#db_type").val()=='sqlite' || jQuery("#db_type").val()=='sqlite3') { jQuery(".hidesqlite").hide(); } else { jQuery(".hidesqlite").show(); } }); diff --git a/htdocs/install/sqlite/functions/functions.sql b/htdocs/install/sqlite3/functions/functions.sql similarity index 100% rename from htdocs/install/sqlite/functions/functions.sql rename to htdocs/install/sqlite3/functions/functions.sql diff --git a/htdocs/install/sqlite/index.html b/htdocs/install/sqlite3/index.html similarity index 100% rename from htdocs/install/sqlite/index.html rename to htdocs/install/sqlite3/index.html From dd2594692e9d6cab9ce6c3c329e606abf1ad43fb Mon Sep 17 00:00:00 2001 From: Guillaume de Lestanville Date: Thu, 5 Mar 2015 17:35:37 +0100 Subject: [PATCH 11/11] Updating compatibility with Sqlite3 - Replace USING syntax by IN SELECT syntax - Fix error on database creation - Removing test on username parameter when installing. --- htdocs/admin/system/database-tables.php | 2 +- htdocs/core/db/sqlite3.class.php | 974 +++++++++--------- htdocs/core/modules/DolibarrModules.class.php | 587 +++++------ htdocs/install/etape1.php | 7 +- index.php | 2 - 5 files changed, 794 insertions(+), 778 deletions(-) delete mode 100644 index.php diff --git a/htdocs/admin/system/database-tables.php b/htdocs/admin/system/database-tables.php index 5ac7292042e..e75cec3f513 100644 --- a/htdocs/admin/system/database-tables.php +++ b/htdocs/admin/system/database-tables.php @@ -180,7 +180,7 @@ else print '
'.$langs->trans("TableName").'
'; print ''; print ''; - print ''; + print ''; print "\n"; $sql = "SELECT name, type FROM sqlite_master where type='table' and name not like 'sqlite%' ORDER BY name"; diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php index f232acb199e..c52578fa579 100644 --- a/htdocs/core/db/sqlite3.class.php +++ b/htdocs/core/db/sqlite3.class.php @@ -37,18 +37,18 @@ class DoliDBSqlite3 extends DoliDB const LABEL='Sqlite3'; //! Version min database const VERSIONMIN='3.0.0'; - //! Resultset of last query - private $_results; + //! Resultset of last query + private $_results; - const WEEK_MONDAY_FIRST=1; - const WEEK_YEAR = 2; - const WEEK_FIRST_WEEKDAY=4; + const WEEK_MONDAY_FIRST=1; + const WEEK_YEAR = 2; + const WEEK_FIRST_WEEKDAY=4; /** * 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 @@ -101,14 +101,14 @@ class DoliDBSqlite3 extends DoliDB $this->database_selected = 1; $this->database_name = $name; - $this->addCustomFunction('IF'); - $this->addCustomFunction('MONTH'); - $this->addCustomFunction('CURTIME'); - $this->addCustomFunction('CURDATE'); - $this->addCustomFunction('WEEK', 1); - $this->addCustomFunction('WEEK', 2); - $this->addCustomFunction('WEEKDAY'); - $this->addCustomFunction('date_format'); + $this->addCustomFunction('IF'); + $this->addCustomFunction('MONTH'); + $this->addCustomFunction('CURTIME'); + $this->addCustomFunction('CURDATE'); + $this->addCustomFunction('WEEK', 1); + $this->addCustomFunction('WEEK', 2); + $this->addCustomFunction('WEEKDAY'); + $this->addCustomFunction('date_format'); //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } else @@ -135,83 +135,83 @@ class DoliDBSqlite3 extends DoliDB */ static function convertSQLFromMysql($line,$type='ddl') { - // Removed empty line if this is a comment line for SVN tagging - if (preg_match('/^--\s\$Id/i',$line)) { - return ''; - } - // Return line if this is a comment - if (preg_match('/^#/i',$line) || preg_match('/^$/i',$line) || preg_match('/^--/i',$line)) - { - return $line; - } - if ($line != "") - { - if ($type == 'auto') - { + // Removed empty line if this is a comment line for SVN tagging + if (preg_match('/^--\s\$Id/i',$line)) { + return ''; + } + // Return line if this is a comment + if (preg_match('/^#/i',$line) || preg_match('/^$/i',$line) || preg_match('/^--/i',$line)) + { + return $line; + } + if ($line != "") + { + if ($type == 'auto') + { if (preg_match('/ALTER TABLE/i',$line)) $type='dml'; else if (preg_match('/CREATE TABLE/i',$line)) $type='dml'; else if (preg_match('/DROP TABLE/i',$line)) $type='dml'; - } + } - if ($type == 'dml') - { + if ($type == 'dml') + { $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); - } + // 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 integer PRIMARY KEY AUTOINCREMENT',$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 integer PRIMARY KEY AUTOINCREMENT',$line); //$line = "-- ".$line." replaced by --\n".$newline; $line=$newline; - } + } - // tinyint type conversion - $line=str_replace('tinyint','smallint',$line); + // tinyint type conversion + $line=str_replace('tinyint','smallint',$line); - // nuke unsigned - $line=preg_replace('/(int\w+|smallint)\s+unsigned/i','\\1',$line); + // nuke unsigned + $line=preg_replace('/(int\w+|smallint)\s+unsigned/i','\\1',$line); - // blob -> text - $line=preg_replace('/\w*blob/i','text',$line); + // 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); + // tinytext/mediumtext -> text + $line=preg_replace('/tinytext/i','text',$line); + $line=preg_replace('/mediumtext/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); + // 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); + // 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); - // unique index(field1,field2) - if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i',$line)) - { - $line=preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i','UNIQUE\(\\1\)',$line); - } + // unique index(field1,field2) + if (preg_match('/unique index\s*\((\w+\s*,\s*\w+)\)/i',$line)) + { + $line=preg_replace('/unique index\s*\((\w+\s*,\s*\w+)\)/i','UNIQUE\(\\1\)',$line); + } - // We remove end of requests "AFTER fieldxxx" - $line=preg_replace('/AFTER [a-z0-9_]+/i','',$line); + // We remove end of requests "AFTER fieldxxx" + $line=preg_replace('/AFTER [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_]+ DROP INDEX/i','DROP INDEX',$line); + // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX + $line=preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i','DROP INDEX',$line); // Translate order to rename fields if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i',$line,$reg)) { - $line = "-- ".$line." replaced by --\n"; + $line = "-- ".$line." replaced by --\n"; $line.= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3]; } @@ -230,12 +230,12 @@ class DoliDBSqlite3 extends DoliDB } // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported - // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity); - if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i',$line,$reg)) - { - $line = "-- ".$line." replaced by --\n"; - $line.= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3]; - } + // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity); + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i',$line,$reg)) + { + $line = "-- ".$line." replaced by --\n"; + $line.= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3]; + } // Translate order to drop foreign keys // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx; @@ -245,62 +245,62 @@ class DoliDBSqlite3 extends DoliDB $line.= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2]; } - // alter table add [unique] [index] (field1, field2 ...) - // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version) - if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i',$line,$reg)) - { - $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.")"; - } - if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$line, $reg)) { - // Pour l'instant les contraintes ne sont pas créées - dol_syslog(get_class().'::query line emptied'); - $line = 'SELECT 0;'; + // alter table add [unique] [index] (field1, field2 ...) + // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version) + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i',$line,$reg)) + { + $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.")"; + } + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$line, $reg)) { + // Pour l'instant les contraintes ne sont pas créées + dol_syslog(get_class().'::query line emptied'); + $line = 'SELECT 0;'; - } + } - //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) { - //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line); - //} + //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) { + //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line); + //} } - // Delete using criteria on other table must not declare twice the deleted table - // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable - if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i',$line,$reg)) - { + // Delete using criteria on other table must not declare twice the deleted table + // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable + 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 - { - $line=preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i','DELETE FROM \\1 USING \\3', $line); - } - } + { + $line=preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i','DELETE FROM \\1 USING \\3', $line); + } + } - // Remove () in the tables in FROM if one table - $line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line); - //print $line."\n"; + // Remove () in the tables in FROM if one table + $line=preg_replace('/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i','FROM \\1',$line); + //print $line."\n"; - // Remove () in the tables in FROM if two table - $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); - //print $line."\n"; + // Remove () in the tables in FROM if two table + $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); + //print $line."\n"; - // Remove () in the tables in FROM if two table - $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); - //print $line."\n"; + // Remove () in the tables in FROM if two table + $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); + //print $line."\n"; - //print "type=".$type." newline=".$line."
\n"; - } + //print "type=".$type." newline=".$line."
\n"; + } - return $line; + return $line; } - /** + /** * Select a database - * + * * @param string $database Name of database * @return boolean true if OK, false if KO - */ + */ function select_db($database) { dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG); @@ -310,7 +310,7 @@ class DoliDBSqlite3 extends DoliDB /** * Connexion to server - * + * * @param string $host database server host * @param string $login login * @param string $passwd password @@ -329,7 +329,7 @@ class DoliDBSqlite3 extends DoliDB if (empty($dir)) $dir=DOL_DATA_ROOT; // With sqlite, port must be in connect parameters //if (! $newport) $newport=3306; - $database_name = $dir.'/database_'.$name.'.sdb'; + $database_name = $dir.'/database_'.$name.'.sdb'; try { /*** connect to SQLite database ***/ //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb'); @@ -349,12 +349,12 @@ class DoliDBSqlite3 extends DoliDB /** * Return version of database server - * + * * @return string Version string */ function getVersion() { - return $this->db->version()['versionString']; + return $this->db->version()['versionString']; } /** @@ -364,10 +364,10 @@ class DoliDBSqlite3 extends DoliDB */ function getDriverInfo() { - // FIXME: Dummy method - // TODO: Implement + // FIXME: Dummy method + // TODO: Implement - return ''; + return ''; } @@ -381,9 +381,9 @@ class DoliDBSqlite3 extends DoliDB { 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); + if ($this->transaction_opened > 0) dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened,LOG_ERR); $this->connected=0; - $this->db->close(); + $this->db->close(); $this->db=null; // Clean this->db return true; } @@ -391,7 +391,7 @@ class DoliDBSqlite3 extends DoliDB } /** - * Execute a SQL request and return the resultset + * Execute a SQL request and return the resultset * * @param string $query SQL query string * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollbock to savepoint if error (this allow to have some request with errors inside global transactions). @@ -407,58 +407,58 @@ class DoliDBSqlite3 extends DoliDB $query = trim($query); $this->error = 0; - // Convert MySQL syntax to SQLite syntax - if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$query, $reg)) { - // Ajout d'une clef étrangère à la table - // procédure de remplacement de la table pour ajouter la contrainte - // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid) - // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)) - $foreignFields = $reg[5]; - $foreignTable = $reg[4]; - $localfields = $reg[3]; - $constraintname=trim($reg[2]); - $tablename=trim($reg[1]); + // Convert MySQL syntax to SQLite syntax + if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i',$query, $reg)) { + // Ajout d'une clef étrangère à la table + // procédure de remplacement de la table pour ajouter la contrainte + // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid) + // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)) + $foreignFields = $reg[5]; + $foreignTable = $reg[4]; + $localfields = $reg[3]; + $constraintname=trim($reg[2]); + $tablename=trim($reg[1]); - $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); + $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='" . $tablename . "'"); - // 1- Renommer la table avec un nom temporaire - $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); + // 1- Renommer la table avec un nom temporaire + $this->query('ALTER TABLE ' . $tablename . ' RENAME TO tmp_' . $tablename); - // 2- Recréer la table avec la contrainte ajoutée + // 2- Recréer la table avec la contrainte ajoutée - // on bricole la requete pour ajouter la contrainte - $descTable = substr($descTable, 0, strlen($descTable) - 1); - $descTable .= ", CONSTRAINT " . $constraintname . " FOREIGN KEY (" . $localfields . ") REFERENCES " .$foreignTable . "(" . $foreignFields . ")"; + // on bricole la requete pour ajouter la contrainte + $descTable = substr($descTable, 0, strlen($descTable) - 1); + $descTable .= ", CONSTRAINT " . $constraintname . " FOREIGN KEY (" . $localfields . ") REFERENCES " .$foreignTable . "(" . $foreignFields . ")"; - // fermeture de l'instruction - $descTable .= ')'; + // fermeture de l'instruction + $descTable .= ')'; - // Création proprement dite de la table - $this->query($descTable); + // Création proprement dite de la table + $this->query($descTable); - // 3- Transférer les données - $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); + // 3- Transférer les données + $this->query('INSERT INTO ' . $tablename . ' SELECT * FROM tmp_' . $tablename); - // 4- Supprimer la table temporaire - $this->query('DROP TABLE tmp_' . $tablename); + // 4- Supprimer la table temporaire + $this->query('DROP TABLE tmp_' . $tablename); - // dummy statement - $query="SELECT 0"; + // dummy statement + $query="SELECT 0"; - } else { - $query=$this->convertSQLFromMysql($query,$type); - } - //print "After convertSQLFromMysql:\n".$query."
\n"; + } else { + $query=$this->convertSQLFromMysql($query,$type); + } + //print "After convertSQLFromMysql:\n".$query."
\n"; - dol_syslog('sql='.$query, LOG_DEBUG); + dol_syslog('sql='.$query, LOG_DEBUG); - // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE) + // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE) try { //$ret = $this->db->exec($query); - $ret = $this->db->query($query); // $ret is a PDO object - if ($ret) { - $ret->queryString = $query; - } + $ret = $this->db->query($query); // $ret is a Sqlite3Result + if ($ret) { + $ret->queryString = $query; + } } catch(Exception $e) { @@ -474,15 +474,15 @@ class DoliDBSqlite3 extends DoliDB $this->lasterror = $this->error(); $this->lasterrno = $this->errno(); - dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); + dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); - $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror; + $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror; - if (preg_match('/[0-9]/',$this->lasterrno)) { + if (preg_match('/[0-9]/',$this->lasterrno)) { $errormsg .= ' ('.$this->lasterrno.')'; } - dol_syslog($errormsg, LOG_ERR); + dol_syslog($errormsg, LOG_ERR); } $this->lastquery=$query; $this->_results = $ret; @@ -502,10 +502,10 @@ class DoliDBSqlite3 extends DoliDB // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion if (! is_object($resultset)) { $resultset=$this->_results; } //return $resultset->fetch(PDO::FETCH_OBJ); - $ret = $resultset->fetchArray(SQLITE3_ASSOC); - if ($ret) { - return (object)$ret; - } + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (object)$ret; + } } @@ -520,10 +520,10 @@ class DoliDBSqlite3 extends DoliDB // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } //return $resultset->fetch(PDO::FETCH_ASSOC); - $ret = $resultset->fetchArray(SQLITE3_ASSOC); - if ($ret) { - return (array)$ret; - } + $ret = $resultset->fetchArray(SQLITE3_ASSOC); + if ($ret) { + return (array)$ret; + } } /** @@ -558,10 +558,10 @@ class DoliDBSqlite3 extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - if (preg_match("/^SELECT/i", $resultset->queryString)) { - return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q"); - } - return 0; + if (preg_match("/^SELECT/i", $resultset->queryString)) { + return $this->db->querySingle("SELECT count(*) FROM (" . $resultset->queryString . ") q"); + } + return 0; } /** @@ -575,21 +575,21 @@ class DoliDBSqlite3 extends DoliDB { // If resultset not provided, we take the last used by connexion if (! is_object($resultset)) { $resultset=$this->_results; } - if (preg_match("/^SELECT/i", $resultset->queryString)) { - return $this->num_rows($resultset); - } + if (preg_match("/^SELECT/i", $resultset->queryString)) { + return $this->num_rows($resultset); + } // mysql necessite un link de base pour cette fonction contrairement // a pqsql qui prend un resultset return $this->db->changes(); } - /** + /** * Free last resultset used. - * + * * @param resultset $resultset Curseur de la requete voulue * @return void - */ + */ function free($resultset=0) { // If resultset not provided, we take the last used by connexion @@ -598,15 +598,15 @@ class DoliDBSqlite3 extends DoliDB if ($resultset && is_object($resultset)) $resultset->finalize(); } - /** + /** * Escape a string to insert data - * + * * @param string $stringtoencode String to escape * @return string String escaped - */ + */ function escape($stringtoencode) { - return Sqlite3::escapeString($stringtoencode); + return Sqlite3::escapeString($stringtoencode); } /** @@ -656,19 +656,19 @@ class DoliDBSqlite3 extends DoliDB }*/ $errno=$this->db->lastErrorCode(); if ($errno=='HY000' || $errno == 0) - { + { if (preg_match('/table.*already exists/i',$this->error)) return 'DB_ERROR_TABLE_ALREADY_EXISTS'; elseif (preg_match('/index.*already exists/i',$this->error)) return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS'; elseif (preg_match('/syntax error/i',$this->error)) return 'DB_ERROR_SYNTAX'; - } - if ($errno=='23000') - { + } + if ($errno=='23000') + { if (preg_match('/column.* not unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; elseif (preg_match('/PRIMARY KEY must be unique/i',$this->error)) return 'DB_ERROR_RECORD_ALREADY_EXISTS'; - } - if ($errno > 1) { - // TODO Voir la liste des messages d'erreur - } + } + if ($errno > 1) { + // TODO Voir la liste des messages d'erreur + } return ($errno?'DB_ERROR_'.$errno:'0'); } @@ -691,8 +691,8 @@ class DoliDBSqlite3 extends DoliDB } /** - * Get last ID after an insert INSERT - * + * Get last ID after an insert INSERT + * * @param string $tab Table name concerned by insert. Ne sert pas sous MySql mais requis pour compatibilite avec Postgresql * @param string $fieldid Field name * @return int Id of row @@ -772,13 +772,13 @@ class DoliDBSqlite3 extends DoliDB /** - * Return connexion ID - * + * Return connexion ID + * * @return string Id connexion */ function DDLGetConnectId() { - return '?'; + return '?'; } @@ -786,7 +786,7 @@ class DoliDBSqlite3 extends DoliDB * Create a new database * 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 - * + * * @param string $database Database name to create * @param string $charset Charset used to store data * @param string $collation Charset used to sort data @@ -815,8 +815,8 @@ class DoliDBSqlite3 extends DoliDB } /** - * List tables into a database - * + * List tables into a database + * * @param string $database Name of database * @param string $table Name of table filter ('xxx%') * @return array List of tables in an array @@ -839,7 +839,7 @@ class DoliDBSqlite3 extends DoliDB /** * List information of columns into a table. - * + * * @param string $table Name of table * @return array Tableau des informations des champs de la table * TODO modify for sqlite @@ -861,7 +861,7 @@ class DoliDBSqlite3 extends DoliDB /** * Create a table into database - * + * * @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 @@ -938,7 +938,7 @@ class DoliDBSqlite3 extends DoliDB /** * Return a pointer of line with description of a table or field - * + * * @param string $table Name of table * @param string $field Optionnel : Name of field if we want description of field * @return resource Resource @@ -954,7 +954,7 @@ class DoliDBSqlite3 extends DoliDB /** * Create a new field into table - * + * * @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] @@ -1000,7 +1000,7 @@ class DoliDBSqlite3 extends DoliDB /** * Update format of a field into a table - * + * * @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 @@ -1011,7 +1011,7 @@ class DoliDBSqlite3 extends DoliDB $sql = "ALTER TABLE ".$table; $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type']; if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') { - $sql.="(".$field_desc['value'].")"; + $sql.="(".$field_desc['value'].")"; } dol_syslog(get_class($this)."::DDLUpdateField ".$sql,LOG_DEBUG); @@ -1023,7 +1023,7 @@ class DoliDBSqlite3 extends DoliDB /** * Drop a field from table - * + * * @param string $table Name of table * @param string $field_name Name of field to drop * @return int <0 if KO, >0 if OK @@ -1043,7 +1043,7 @@ class DoliDBSqlite3 extends DoliDB /** * Create a user and privileges to connect to database (even if database does not exists yet) - * + * * @param string $dolibarr_main_db_host Ip serveur * @param string $dolibarr_main_db_user Nom user a creer * @param string $dolibarr_main_db_pass Mot de passe user a creer @@ -1088,21 +1088,21 @@ class DoliDBSqlite3 extends DoliDB return 1; } - /** + /** * Return charset used to store data in database - * + * * @return string Charset - */ + */ function getDefaultCharacterSetDatabase() { return 'UTF-8'; } - /** + /** * Return list of available charset that can be used to store data in database - * + * * @return array List of Charset - */ + */ function getListOfCharacterSet() { $liste = array(); @@ -1112,21 +1112,21 @@ class DoliDBSqlite3 extends DoliDB return $liste; } - /** + /** * Return collation used in database - * + * * @return string Collation value - */ + */ function getDefaultCollationDatabase() { return 'UTF-8'; } - /** + /** * Return list of available collation that can be used for database - * + * * @return array List of Collation - */ + */ function getListOfCollation() { $liste = array(); @@ -1136,12 +1136,12 @@ class DoliDBSqlite3 extends DoliDB return $liste; } - /** + /** * Return full path of dump program - * + * * @return string Full path of dump program - */ - function getPathOfDump() + */ + function getPathOfDump() { $fullpathofdump='/pathtomysqldump/mysqldump'; @@ -1155,11 +1155,11 @@ class DoliDBSqlite3 extends DoliDB return $fullpathofdump; } - /** + /** * Return full path of restore program - * + * * @return string Full path of restore program - */ + */ function getPathOfRestore() { $fullpathofimport='/pathtomysql/mysql'; @@ -1174,61 +1174,65 @@ class DoliDBSqlite3 extends DoliDB return $fullpathofimport; } - /** - * Return value of server parameters - * + /** + * Return value of server parameters + * * @param string $filter Filter list on a particular value * @return array Array of key-values (key=>value) - */ + */ function getServerParametersValues($filter='') { $result=array(); - static $pragmas; - if (! isset($pragmas)) { - // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur - // indépendante de la base de données. - // cf. http://www.sqlite.org/pragma.html - $pragmas = array( - 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', - 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', + static $pragmas; + if (! isset($pragmas)) { + // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur + // indépendante de la base de données. + // cf. http://www.sqlite.org/pragma.html + $pragmas = array( + 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size', + 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list', 'compile_options', 'data_version', /*'database_list',*/ - 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count', - 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check', - 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode', - 'max_page_count', 'page_count', 'page_size', 'parser_trace', - 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers', - 'reverse_unordered_selects', 'schema_version', 'user_version', - 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit', - 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', - 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', - 'wal_autocheckpoint', - ); - } + 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count', + 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check', + 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode', + 'max_page_count', 'page_count', 'page_size', 'parser_trace', + 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers', + 'reverse_unordered_selects', 'schema_version', 'user_version', + 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit', + 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads', + 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace', + 'wal_autocheckpoint', + ); + } - // TODO prendre en compte le filtre - foreach($pragmas as $var) { - $sql = "PRAGMA $var"; - $resql=$this->query($sql); - if ($resql) - { - $obj = $this->fetch_row($resql); - //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG); - $result[$var] = $obj[0]; - } - } + // TODO prendre en compte le filtre + foreach($pragmas as $var) { + $sql = "PRAGMA $var"; + $resql=$this->query($sql); + if ($resql) + { + $obj = $this->fetch_row($resql); + //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG); + $result[$var] = $obj[0]; + } + else { + // TODO Récupérer le message + $result[$var] = 'FAIL'; + } + } return $result; } - /** - * Return value of server status - * + /** + * Return value of server status + * * @param string $filter Filter list on a particular value * @return array Array of key-values (key=>value) - */ + */ function getServerStatusValues($filter='') { $result=array(); - /* + /* $sql='SHOW STATUS'; if ($filter) $sql.=" LIKE '".$this->escape($filter)."'"; $resql=$this->query($sql); @@ -1236,243 +1240,243 @@ class DoliDBSqlite3 extends DoliDB { while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value; } - */ + */ return $result; } - /** - * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees. - * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être - * statique et publique. Le nombre de parametres est determine automatiquement. - * @param string $name Le nom de la fonction a definir dans Sqlite - */ - private function addCustomFunction($name, $arg_count = -1) { - if ($this->db) { - $localname = __CLASS__ . '::' . 'db_' . $name; - $reflectClass = new ReflectionClass(__CLASS__); - $reflectFunction = $reflectClass->getMethod('db_' . $name); - if ($arg_count < 0) { - $arg_count = $reflectFunction->getNumberOfParameters(); - } - if (!$this->db->createFunction($name, $localname , $arg_count)) { - $this->error = "unable to create custom function '$name'"; - } - } - } + /** + * Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees. + * Note: le nom de la fonction personnalisee est prefixee par 'db_'. La fonction doit être + * statique et publique. Le nombre de parametres est determine automatiquement. + * @param string $name Le nom de la fonction a definir dans Sqlite + */ + private function addCustomFunction($name, $arg_count = -1) { + if ($this->db) { + $localname = __CLASS__ . '::' . 'db_' . $name; + $reflectClass = new ReflectionClass(__CLASS__); + $reflectFunction = $reflectClass->getMethod('db_' . $name); + if ($arg_count < 0) { + $arg_count = $reflectFunction->getNumberOfParameters(); + } + if (!$this->db->createFunction($name, $localname , $arg_count)) { + $this->error = "unable to create custom function '$name'"; + } + } + } - /** - * Cette fonction est l'equivalent de la fonction MONTH de MySql. - * @param string $date - * @return integer - */ - public static function db_MONTH($date) { - return date('n', strtotime($date)); - } + /** + * Cette fonction est l'equivalent de la fonction MONTH de MySql. + * @param string $date + * @return integer + */ + public static function db_MONTH($date) { + return date('n', strtotime($date)); + } - /** - * calcule du numéro de semaine - * - * @param string date - * @param int mode - */ - public static function db_WEEK($date, $mode = 0) { - $arr = date_parse($date); - $calc_year = 0; - return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year); - } + /** + * calcule du numéro de semaine + * + * @param string date + * @param int mode + */ + public static function db_WEEK($date, $mode = 0) { + $arr = date_parse($date); + $calc_year = 0; + return self::calc_week($arr['year'], $arr['month'], $arr['day'], self::week_mode($mode), $calc_year); + } - public static function db_CURDATE() { - return date('Y-m-d'); - } + public static function db_CURDATE() { + return date('Y-m-d'); + } - public static function db_CURTIME() { - return date('H:i:s'); - } + public static function db_CURTIME() { + return date('H:i:s'); + } - public static function db_WEEKDAY($date) { - $arr = date_parse($date); - return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0); + public static function db_WEEKDAY($date) { + $arr = date_parse($date); + return self::calc_weekday(self::calc_daynr($arr['year'], $arr['month'], $arr['day']), 0); - } + } - /** - * Cette fonction est l'equivelent de la fonction date_format de MySQL. + /** + * Cette fonction est l'equivelent de la fonction date_format de MySQL. * @staticvar string $mysql_replacement Les symboles formatage a remplacer - * @param string $date la date dans un format ISO - * @param string $format la chaine de formatage - * @return string La date formatee. - */ - public static function db_date_format($date, $format) { - static $mysql_replacement; - if (! isset($mysql_replacement)) { - $mysql_replacement = array( - '%' => '%', - 'a' => 'D', - 'b' => 'M', - 'c' => 'n', - 'D' => 'jS', - 'd' => 'd', - 'e' => 'j', - 'f' => 'u', - 'H' => 'H', - 'h' => 'h', - 'I' => 'h', - 'i' => 'i', - 'k' => 'H', - 'l' => 'g', - 'M' => 'F', - 'm' => 'm', - 'p' => 'A', - 'r' => 'h:i:s A', - 'S' => 's', - 's' => 's', - 'T' => 'H:i:s', - 'W' => 'l', - 'w' => 'w', - 'Y' => 'Y', - 'y' => 'y', - ); - } + * @param string $date la date dans un format ISO + * @param string $format la chaine de formatage + * @return string La date formatee. + */ + public static function db_date_format($date, $format) { + static $mysql_replacement; + if (! isset($mysql_replacement)) { + $mysql_replacement = array( + '%' => '%', + 'a' => 'D', + 'b' => 'M', + 'c' => 'n', + 'D' => 'jS', + 'd' => 'd', + 'e' => 'j', + 'f' => 'u', + 'H' => 'H', + 'h' => 'h', + 'I' => 'h', + 'i' => 'i', + 'k' => 'H', + 'l' => 'g', + 'M' => 'F', + 'm' => 'm', + 'p' => 'A', + 'r' => 'h:i:s A', + 'S' => 's', + 's' => 's', + 'T' => 'H:i:s', + 'W' => 'l', + 'w' => 'w', + 'Y' => 'Y', + 'y' => 'y', + ); + } - $fmt = ''; - $lg = strlen($format); - $state = 0; - $timestamp = strtotime($date); - $yday = date('z', $timestamp); - $month = (integer)date("n", $timestamp); - $year = (integer)date("Y", $timestamp); - $day = (integer)date("d", $timestamp); - for($idx = 0; $idx < $lg; ++$idx) { - $char = $format[$idx]; - if ($state == 0) { - if ($char == '%') { - $state = 1; - } else { - $fmt .= $char; - } - } - elseif ($state == 1) { - if (array_key_exists($char, $mysql_replacement)) { - $fmt .= $mysql_replacement[$char]; - } else { - $calc_year = 0; - switch ($char) { + $fmt = ''; + $lg = strlen($format); + $state = 0; + $timestamp = strtotime($date); + $yday = date('z', $timestamp); + $month = (integer)date("n", $timestamp); + $year = (integer)date("Y", $timestamp); + $day = (integer)date("d", $timestamp); + for($idx = 0; $idx < $lg; ++$idx) { + $char = $format[$idx]; + if ($state == 0) { + if ($char == '%') { + $state = 1; + } else { + $fmt .= $char; + } + } + elseif ($state == 1) { + if (array_key_exists($char, $mysql_replacement)) { + $fmt .= $mysql_replacement[$char]; + } else { + $calc_year = 0; + switch ($char) { case 'j': // day of the year 001 - $char = sprintf("%03d", $yday+1); - break; - case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year)); - break; - case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); - break; - case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche - $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); - break; - case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi - $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); - break; - case 'X': - self::calc_week($year, $month, $day, 6, $calc_year); - $char = sprintf("%04d", $calc_year); - break; - case 'x': - self::calc_week($year, $month, $day, 3, $calc_year); - $char = sprintf("%04d", $calc_year); - break; - } - $fmt .= $char; - } - $state = 0; - } - } - return date($fmt, strtotime($date)); - } + $char = sprintf("%03d", $yday+1); + break; + case 'U': // mode 0: semaine 0 = premiere semaine complète qui commence un dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 4, $calc_year)); + break; + case 'u': // mode 1: semaine 0 = première semaine de 4 jours. Début le dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 1, $calc_year)); + break; + case 'V': // mode 2: semaine 1 = premiere semaine complète qui commence un dimanche + $char = sprintf("%02d", self::calc_week($year, $month, $day, 6, $calc_year)); + break; + case 'v': // mode 3: semaine 1 = premiere semaine de 4 jours. Début le lundi + $char = sprintf("%02d", self::calc_week($year, $month, $day, 3, $calc_year)); + break; + case 'X': + self::calc_week($year, $month, $day, 6, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + case 'x': + self::calc_week($year, $month, $day, 3, $calc_year); + $char = sprintf("%04d", $calc_year); + break; + } + $fmt .= $char; + } + $state = 0; + } + } + return date($fmt, strtotime($date)); + } - /** - * Equivalent de la fonction MySQL IF - * @param boolean $test Le resultat du test - * @param mixed $true_part Partie a retourner si vrai - * @param mixed $false_part Partie a retourner si faux - * @return mixed Partie selectionnee en fonction du test - */ - public static function db_IF($test, $true_part, $false_part) { - return ( $test ) ? $true_part : $false_part; - } + /** + * Equivalent de la fonction MySQL IF + * @param boolean $test Le resultat du test + * @param mixed $true_part Partie a retourner si vrai + * @param mixed $false_part Partie a retourner si faux + * @return mixed Partie selectionnee en fonction du test + */ + public static function db_IF($test, $true_part, $false_part) { + return ( $test ) ? $true_part : $false_part; + } - // Adapté de mytime.c des sources de mariadb - // fonction calc_daynr - private static function calc_daynr($year, $month, $day) { - $y = $year; - if ($y == 0 && $month == 0) return 0; - $num = (365* $y + 31 * ($month - 1) + $day); - if ($month <= 2) { - $y--; } - else { - $num -= floor(($month * 4 + 23) / 10); - } - $temp = floor(($y / 100 + 1) * 3 / 4); - return $num + floor($y / 4) - $temp; - } + // Adapté de mytime.c des sources de mariadb + // fonction calc_daynr + private static function calc_daynr($year, $month, $day) { + $y = $year; + if ($y == 0 && $month == 0) return 0; + $num = (365* $y + 31 * ($month - 1) + $day); + if ($month <= 2) { + $y--; } + else { + $num -= floor(($month * 4 + 23) / 10); + } + $temp = floor(($y / 100 + 1) * 3 / 4); + return $num + floor($y / 4) - $temp; + } - private static function calc_weekday($daynr, $sunday_first_day_of_week) { - $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7); - return $ret; - } + private static function calc_weekday($daynr, $sunday_first_day_of_week) { + $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7); + return $ret; + } - private static function calc_days_in_year($year) - { - return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365); - } + private static function calc_days_in_year($year) + { + return (($year & 3) == 0 && ($year%100 || ($year%400 == 0 && $year)) ? 366 : 365); + } - private static function week_mode($mode) { - $week_format= ($mode & 7); - if (!($week_format & self::WEEK_MONDAY_FIRST)) { - $week_format^= self::WEEK_FIRST_WEEKDAY; - } - return $week_format; - } + private static function week_mode($mode) { + $week_format= ($mode & 7); + if (!($week_format & self::WEEK_MONDAY_FIRST)) { + $week_format^= self::WEEK_FIRST_WEEKDAY; + } + return $week_format; + } - private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) { - $daynr=self::calc_daynr($year,$month,$day); - $first_daynr=self::calc_daynr($year,1,1); - $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0; - $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0; - $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0; + private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year) { + $daynr=self::calc_daynr($year,$month,$day); + $first_daynr=self::calc_daynr($year,1,1); + $monday_first= ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0; + $week_year= ($week_behaviour & self::WEEK_YEAR) ? 1 : 0; + $first_weekday= ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0; - $weekday=self::calc_weekday($first_daynr, !$monday_first); - $calc_year=$year; + $weekday=self::calc_weekday($first_daynr, !$monday_first); + $calc_year=$year; - if ($month == 1 && $day <= 7-$weekday) - { - if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) - return 0; - $week_year= 1; - $calc_year--; - $first_daynr-= ($days=self::calc_days_in_year($calc_year)); - $weekday= ($weekday + 53*7- $days) % 7; - } + if ($month == 1 && $day <= 7-$weekday) + { + if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) + return 0; + $week_year= 1; + $calc_year--; + $first_daynr-= ($days=self::calc_days_in_year($calc_year)); + $weekday= ($weekday + 53*7- $days) % 7; + } - if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) { - $days= $daynr - ($first_daynr+ (7-$weekday)); - } - else { - $days= $daynr - ($first_daynr - $weekday); - } + if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) { + $days= $daynr - ($first_daynr+ (7-$weekday)); + } + else { + $days= $daynr - ($first_daynr - $weekday); + } - if ($week_year && $days >= 52*7) - { - $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7; - if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) - { - $calc_year++; - return 1; - } - } - return floor($days/7+1); - } + if ($week_year && $days >= 52*7) + { + $weekday= ($weekday + self::calc_days_in_year($calc_year)) % 7; + if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) + { + $calc_year++; + return 1; + } + } + return floor($days/7+1); + } } diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 0b0ceb5460c..017d1eb8662 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -39,166 +39,166 @@ abstract class DolibarrModules */ public $db; - /** - * @var string Relative path to module style sheet - * @deprecated - */ - public $style_sheet = ''; + /** + * @var string Relative path to module style sheet + * @deprecated + */ + public $style_sheet = ''; - /** - * @var array Paths to create when module is activated - */ - public $dirs = array(); + /** + * @var array Paths to create when module is activated + */ + public $dirs = array(); - /** - * @var array Module boxes - */ - public $boxes = array(); + /** + * @var array Module boxes + */ + public $boxes = array(); - /** - * @var array Module constants - */ - public $const = array(); + /** + * @var array Module constants + */ + public $const = array(); - /** - * @var array Module access rights - */ - public $rights; + /** + * @var array Module access rights + */ + public $rights; - /** - * @var string Module access rights family - */ - public $rights_class; + /** + * @var string Module access rights family + */ + public $rights_class; - /** - * @var array Module menu entries - */ - public $menu = array(); + /** + * @var array Module menu entries + */ + public $menu = array(); - /** - * @var array Module parts - * array( - * // Set this to 1 if module has its own trigger directory (/mymodule/core/triggers) - * 'triggers' => 0, - * // Set this to 1 if module has its own login method directory (/mymodule/core/login) + /** + * @var array Module parts + * array( + * // Set this to 1 if module has its own trigger directory (/mymodule/core/triggers) + * 'triggers' => 0, + * // Set this to 1 if module has its own login method directory (/mymodule/core/login) * 'login' => 0, - * // Set this to 1 if module has its own substitution function file (/mymodule/core/substitutions) + * // Set this to 1 if module has its own substitution function file (/mymodule/core/substitutions) * 'substitutions' => 0, - * // Set this to 1 if module has its own menus handler directory (/mymodule/core/menus) + * // Set this to 1 if module has its own menus handler directory (/mymodule/core/menus) * 'menus' => 0, - * // Set this to 1 if module has its own theme directory (/mymodule/theme) + * // Set this to 1 if module has its own theme directory (/mymodule/theme) * 'theme' => 0, - * // Set this to 1 if module overwrite template dir (/mymodule/core/tpl) - * 'tpl' => 0, - * // Set this to 1 if module has its own barcode directory (/mymodule/core/modules/barcode) + * // Set this to 1 if module overwrite template dir (/mymodule/core/tpl) + * 'tpl' => 0, + * // Set this to 1 if module has its own barcode directory (/mymodule/core/modules/barcode) * 'barcode' => 0, - * // Set this to 1 if module has its own models directory (/mymodule/core/modules/xxx) + * // Set this to 1 if module has its own models directory (/mymodule/core/modules/xxx) * 'models' => 0, - * // Set this to relative path of css file if module has its own css file + * // Set this to relative path of css file if module has its own css file * 'css' => '/mymodule/css/mymodule.css.php', - * // Set this to relative path of js file if module must load a js on all pages + * // Set this to relative path of js file if module must load a js on all pages * 'js' => '/mymodule/js/mymodule.js', - * // Set here all hooks context managed by module + * // Set here all hooks context managed by module * 'hooks' => array('hookcontext1','hookcontext2'), - * // Set here all workflow context managed by module + * // Set here all workflow context managed by module * 'workflow' => array( - * 'WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2' = >array( - * 'enabled' => '! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', - * 'picto'=>'yourpicto@mymodule' - * ) - * ) - * ) - */ - public $module_parts = array(); + * 'WORKFLOW_MODULE1_YOURACTIONTYPE_MODULE2' = >array( + * 'enabled' => '! empty($conf->module1->enabled) && ! empty($conf->module2->enabled)', + * 'picto'=>'yourpicto@mymodule' + * ) + * ) + * ) + */ + public $module_parts = array(); - /** - * @var string Module documents ? - * @deprecated Seems unused anywhere - */ - public $docs; + /** + * @var string Module documents ? + * @deprecated Seems unused anywhere + */ + public $docs; - /** - * @var string ? - * @deprecated Seems unused anywhere - */ - public $dbversion = "-"; + /** + * @var string ? + * @deprecated Seems unused anywhere + */ + public $dbversion = "-"; - /** - * @var string Error message - */ - public $error; + /** + * @var string Error message + */ + public $error; - /** - * @var int Module unique ID - */ - public $numero; + /** + * @var int Module unique ID + */ + public $numero; - /** - * @var string Module name - */ - public $name; + /** + * @var string Module name + */ + public $name; - /** - * @var string Module version - */ - public $version; + /** + * @var string Module version + */ + public $version; - /** - * @var string Module description - */ - public $description; + /** + * @var string Module description + */ + public $description; - /** - * @var string[] Module language files - */ - public $langfiles; + /** + * @var string[] Module language files + */ + public $langfiles; - /** - * @var string Module export code - */ - public $export_code; + /** + * @var string Module export code + */ + public $export_code; - /** - * @var string Module export label - */ - public $export_label; + /** + * @var string Module export label + */ + public $export_label; - /** - * @var string Module import code - */ - public $import_code; + /** + * @var string Module import code + */ + public $import_code; - /** - * @var string Module import label - */ - public $import_label; + /** + * @var string Module import label + */ + public $import_label; - /** - * @var string Module constant name - */ - public $const_name; + /** + * @var string Module constant name + */ + public $const_name; - /** - * @var bool Module can't be disabled - */ - public $always_enabled; + /** + * @var bool Module can't be disabled + */ + public $always_enabled; - /** - * @var bool Module is enabled globally (Multicompany support) - */ - public $core_enabled; + /** + * @var bool Module is enabled globally (Multicompany support) + */ + public $core_enabled; - /** - * Enables a module. - * Inserts all informations into database - * + /** + * Enables a module. + * Inserts all informations into database + * * @param array $array_sql SQL requests to be executed when enabling module - * @param string $options String with options when disabling module: - * 'noboxes' = Do not insert boxes - * 'newboxdefonly' = For boxes, insert def of boxes only and not boxes activation - * - * @return int 1 if OK, 0 if KO - */ + * @param string $options String with options when disabling module: + * 'noboxes' = Do not insert boxes + * 'newboxdefonly' = For boxes, insert def of boxes only and not boxes activation + * + * @return int 1 if OK, 0 if KO + */ function _init($array_sql, $options='') { global $conf; @@ -232,12 +232,12 @@ abstract class DolibarrModules // Execute addons requests $num=count($array_sql); - for ($i = 0; $i < $num; $i++) + for ($i = 0; $i < $num; $i++) { if (! $err) { $val=$array_sql[$i]; - $sql=$val; + $sql=$val; $ignoreerror=0; if (is_array($val)) { @@ -367,12 +367,12 @@ abstract class DolibarrModules // If module name translation using it's unique id does not exists, we take use its name to find translation if (is_array($this->langfiles)) { - foreach($this->langfiles as $val) - { - if ($val) $langs->load($val); - } + foreach($this->langfiles as $val) + { + if ($val) $langs->load($val); + } } - return $langs->trans($this->name); + return $langs->trans($this->name); } } @@ -389,20 +389,20 @@ abstract class DolibarrModules if ($langs->trans("Module".$this->numero."Desc") != ("Module".$this->numero."Desc")) { - // If module description translation exists + // If module description translation exists return $langs->trans("Module".$this->numero."Desc"); } else - { + { // If module description translation using it's unique id does not exists, we take use its name to find translation if (is_array($this->langfiles)) { - foreach($this->langfiles as $val) - { - if ($val) $langs->load($val); - } + foreach($this->langfiles as $val) + { + if ($val) $langs->load($val); + } } - return $langs->trans($this->description); + return $langs->trans($this->description); } } @@ -429,7 +429,7 @@ abstract class DolibarrModules else $ret=$langs->trans("VersionUnknown"); if (preg_match('/_deprecated/',$this->version)) $ret.=' ('.$langs->trans("Deprecated").')'; - return $ret; + return $ret; } @@ -582,9 +582,9 @@ abstract class DolibarrModules global $conf; $error=0; - $dirfound=0; + $dirfound=0; - if (empty($reldir)) return 1; + if (empty($reldir)) return 1; include_once DOL_DOCUMENT_ROOT . '/core/lib/admin.lib.php'; @@ -599,10 +599,10 @@ abstract class DolibarrModules $handle=@opendir($dir); // Dir may not exists if (is_resource($handle)) { - $dirfound++; + $dirfound++; - // Run llx_mytable.sql files - while (($file = readdir($handle))!==false) + // Run llx_mytable.sql files + while (($file = readdir($handle))!==false) { if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data') { @@ -613,8 +613,8 @@ abstract class DolibarrModules rewinddir($handle); - // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql) - while (($file = readdir($handle))!==false) + // Run llx_mytable.key.sql files (Must be done after llx_mytable.sql) + while (($file = readdir($handle))!==false) { if (preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'llx_' && substr($file,0,4) != 'data') { @@ -626,7 +626,7 @@ abstract class DolibarrModules rewinddir($handle); // Run data_xxx.sql files (Must be done after llx_mytable.key.sql) - while (($file = readdir($handle))!==false) + while (($file = readdir($handle))!==false) { if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,4) == 'data') { @@ -638,7 +638,7 @@ abstract class DolibarrModules rewinddir($handle); // Run update_xxx.sql files - while (($file = readdir($handle))!==false) + while (($file = readdir($handle))!==false) { if (preg_match('/\.sql$/i',$file) && ! preg_match('/\.key\.sql$/i',$file) && substr($file,0,6) == 'update') { @@ -671,9 +671,9 @@ abstract class DolibarrModules */ function insert_boxes($option='') { - require_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php'; + require_once DOL_DOCUMENT_ROOT . '/core/class/infobox.class.php'; - global $conf; + global $conf; $err=0; @@ -681,8 +681,8 @@ abstract class DolibarrModules { $pos_name = InfoBox::getListOfPagesForBoxes(); - foreach ($this->boxes as $key => $value) - { + foreach ($this->boxes as $key => $value) + { $file = isset($this->boxes[$key]['file'])?$this->boxes[$key]['file']:''; $note = isset($this->boxes[$key]['note'])?$this->boxes[$key]['note']:''; $enabledbydefaulton = isset($this->boxes[$key]['enabledbydefaulton'])?$this->boxes[$key]['enabledbydefaulton']:'Home'; @@ -724,15 +724,15 @@ abstract class DolibarrModules foreach ($pos_name as $key2 => $val2) { - //print 'key2='.$key2.'-val2='.$val2."
\n"; + //print 'key2='.$key2.'-val2='.$val2."
\n"; if ($enabledbydefaulton && $val2 != $enabledbydefaulton) continue; // Not enabled by default onto this page. - $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (box_id,position,box_order,fk_user,entity)"; - $sql.= " VALUES (".$lastid.", ".$key2.", '0', 0, ".$conf->entity.")"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."boxes (box_id,position,box_order,fk_user,entity)"; + $sql.= " VALUES (".$lastid.", ".$key2.", '0', 0, ".$conf->entity.")"; - dol_syslog(get_class($this)."::insert_boxes onto page ".$key2."=".$val2."", LOG_DEBUG); - $resql=$this->db->query($sql); - if (! $resql) $err++; + dol_syslog(get_class($this)."::insert_boxes onto page ".$key2."=".$val2."", LOG_DEBUG); + $resql=$this->db->query($sql); + if (! $resql) $err++; } } @@ -741,7 +741,7 @@ abstract class DolibarrModules $this->db->commit(); } else - { + { $this->error=$this->db->lasterror(); $this->db->rollback(); } @@ -781,11 +781,22 @@ abstract class DolibarrModules if (empty($file)) $file = isset($this->boxes[$key][1])?$this->boxes[$key][1]:''; // For backward compatibility - $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes"; - $sql.= " USING ".MAIN_DB_PREFIX."boxes, ".MAIN_DB_PREFIX."boxes_def"; - $sql.= " WHERE ".MAIN_DB_PREFIX."boxes.box_id = ".MAIN_DB_PREFIX."boxes_def.rowid"; - $sql.= " AND ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."'"; - $sql.= " AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity; + if ($this->db->type == 'sqlite3') { + // sqlite doesn't support "USING" syntax. + // TODO: remove this dependency. + $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes "; + $sql .= "WHERE ".MAIN_DB_PREFIX."boxes.box_id IN ("; + $sql .= "SELECT ".MAIN_DB_PREFIX."boxes_def.rowid "; + $sql .= "FROM ".MAIN_DB_PREFIX."boxes_def "; + $sql .= "WHERE ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."') "; + $sql .= "AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity; + } else { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."boxes"; + $sql.= " USING ".MAIN_DB_PREFIX."boxes, ".MAIN_DB_PREFIX."boxes_def"; + $sql.= " WHERE ".MAIN_DB_PREFIX."boxes.box_id = ".MAIN_DB_PREFIX."boxes_def.rowid"; + $sql.= " AND ".MAIN_DB_PREFIX."boxes_def.file = '".$this->db->escape($file)."'"; + $sql.= " AND ".MAIN_DB_PREFIX."boxes.entity = ".$conf->entity; + } dol_syslog(get_class($this)."::delete_boxes", LOG_DEBUG); $resql=$this->db->query($sql); @@ -1027,54 +1038,54 @@ abstract class DolibarrModules if (empty($r_type)) $r_type='w'; - // Search if perm already present - $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."rights_def"; - $sql.= " WHERE id = ".$r_id." AND entity = ".$entity; - $resqlselect=$this->db->query($sql); + // Search if perm already present + $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."rights_def"; + $sql.= " WHERE id = ".$r_id." AND entity = ".$entity; + $resqlselect=$this->db->query($sql); - $obj = $this->db->fetch_object($resqlselect); + $obj = $this->db->fetch_object($resqlselect); if ($obj->nb == 0) { - if (dol_strlen($r_perms) ) - { - if (dol_strlen($r_subperms) ) - { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def"; - $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)"; - $sql.= " VALUES "; - $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')"; - } - else - { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def"; - $sql.= " (id, entity, libelle, module, type, bydefault, perms)"; - $sql.= " VALUES "; - $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."')"; - } - } - else - { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def "; - $sql .= " (id, entity, libelle, module, type, bydefault)"; - $sql .= " VALUES "; - $sql .= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.")"; - } + if (dol_strlen($r_perms) ) + { + if (dol_strlen($r_subperms) ) + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def"; + $sql.= " (id, entity, libelle, module, type, bydefault, perms, subperms)"; + $sql.= " VALUES "; + $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."','".$r_subperms."')"; + } + else + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def"; + $sql.= " (id, entity, libelle, module, type, bydefault, perms)"; + $sql.= " VALUES "; + $sql.= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.",'".$r_perms."')"; + } + } + else + { + $sql = "INSERT INTO ".MAIN_DB_PREFIX."rights_def "; + $sql .= " (id, entity, libelle, module, type, bydefault)"; + $sql .= " VALUES "; + $sql .= "(".$r_id.",".$entity.",'".$this->db->escape($r_desc)."','".$r_modul."','".$r_type."',".$r_def.")"; + } - $resqlinsert=$this->db->query($sql,1); + $resqlinsert=$this->db->query($sql,1); - if (! $resqlinsert) - { - if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS") - { - $this->error=$this->db->lasterror(); - $err++; - break; - } - else dol_syslog(get_class($this)."::insert_permissions record already exists", LOG_INFO); + if (! $resqlinsert) + { + if ($this->db->errno() != "DB_ERROR_RECORD_ALREADY_EXISTS") + { + $this->error=$this->db->lasterror(); + $err++; + break; + } + else dol_syslog(get_class($this)."::insert_permissions record already exists", LOG_INFO); - } + } - $this->db->free($resqlinsert); + $this->db->free($resqlinsert); } $this->db->free($resqlselect); @@ -1082,9 +1093,9 @@ abstract class DolibarrModules // If we want to init permissions on admin users if ($reinitadminperms) { - if (! class_exists('User')) { - require DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; - } + if (! class_exists('User')) { + require DOL_DOCUMENT_ROOT . '/user/class/user.class.php'; + } $sql="SELECT rowid FROM ".MAIN_DB_PREFIX."user WHERE admin = 1"; dol_syslog(get_class($this)."::insert_permissions Search all admin users", LOG_DEBUG); $resqlseladmin=$this->db->query($sql,1); @@ -1099,7 +1110,7 @@ abstract class DolibarrModules $tmpuser=new User($this->db); $tmpuser->fetch($obj2->rowid); if (!empty($tmpuser->id)) { - $tmpuser->addrights($r_id); + $tmpuser->addrights($r_id); } $i++; } @@ -1158,7 +1169,7 @@ abstract class DolibarrModules */ function insert_menus() { - global $user; + global $user; require_once DOL_DOCUMENT_ROOT . '/core/class/menubase.class.php'; @@ -1415,68 +1426,68 @@ abstract class DolibarrModules */ function insert_module_parts() { - global $conf; + global $conf; - $error=0; - $entity=$conf->entity; + $error=0; + $entity=$conf->entity; - if (is_array($this->module_parts) && ! empty($this->module_parts)) - { - foreach($this->module_parts as $key => $value) - { + if (is_array($this->module_parts) && ! empty($this->module_parts)) + { + foreach($this->module_parts as $key => $value) + { if (is_array($value) && count($value) == 0) continue; // Discard empty arrays - $newvalue = $value; + $newvalue = $value; - // Serialize array parameters - if (is_array($value)) - { - // Can defined other parameters - if (is_array($value['data']) && ! empty($value['data'])) - { - $newvalue = json_encode($value['data']); - if (isset($value['entity'])) $entity = $value['entity']; - } - else - { - $newvalue = json_encode($value); - } - } + // Serialize array parameters + if (is_array($value)) + { + // Can defined other parameters + if (is_array($value['data']) && ! empty($value['data'])) + { + $newvalue = json_encode($value['data']); + if (isset($value['entity'])) $entity = $value['entity']; + } + else + { + $newvalue = json_encode($value); + } + } - $sql = "INSERT INTO ".MAIN_DB_PREFIX."const ("; - $sql.= "name"; - $sql.= ", type"; - $sql.= ", value"; - $sql.= ", note"; - $sql.= ", visible"; - $sql.= ", entity"; - $sql.= ")"; - $sql.= " VALUES ("; - $sql.= $this->db->encrypt($this->const_name."_".strtoupper($key), 1); - $sql.= ", 'chaine'"; - $sql.= ", ".$this->db->encrypt($newvalue, 1); - $sql.= ", null"; - $sql.= ", '0'"; - $sql.= ", ".$entity; - $sql.= ")"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."const ("; + $sql.= "name"; + $sql.= ", type"; + $sql.= ", value"; + $sql.= ", note"; + $sql.= ", visible"; + $sql.= ", entity"; + $sql.= ")"; + $sql.= " VALUES ("; + $sql.= $this->db->encrypt($this->const_name."_".strtoupper($key), 1); + $sql.= ", 'chaine'"; + $sql.= ", ".$this->db->encrypt($newvalue, 1); + $sql.= ", null"; + $sql.= ", '0'"; + $sql.= ", ".$entity; + $sql.= ")"; - dol_syslog(get_class($this)."::insert_const_".$key."", LOG_DEBUG); - $resql=$this->db->query($sql,1); - if (! $resql) - { - if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS') - { - $error++; - $this->error=$this->db->lasterror(); - } - else - { - dol_syslog(get_class($this)."::insert_const_".$key." Record already exists.", LOG_WARNING); - } - } - } - } - return $error; + dol_syslog(get_class($this)."::insert_const_".$key."", LOG_DEBUG); + $resql=$this->db->query($sql,1); + if (! $resql) + { + if ($this->db->lasterrno() != 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $error++; + $this->error=$this->db->lasterror(); + } + else + { + dol_syslog(get_class($this)."::insert_const_".$key." Record already exists.", LOG_WARNING); + } + } + } + } + return $error; } /** @@ -1486,31 +1497,31 @@ abstract class DolibarrModules */ function delete_module_parts() { - global $conf; + global $conf; - $err=0; - $entity=$conf->entity; + $err=0; + $entity=$conf->entity; - if (is_array($this->module_parts) && ! empty($this->module_parts)) - { - foreach($this->module_parts as $key => $value) - { - // If entity is defined - if (is_array($value) && isset($value['entity'])) $entity = $value['entity']; + if (is_array($this->module_parts) && ! empty($this->module_parts)) + { + foreach($this->module_parts as $key => $value) + { + // If entity is defined + if (is_array($value) && isset($value['entity'])) $entity = $value['entity']; - $sql = "DELETE FROM ".MAIN_DB_PREFIX."const"; - $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->const_name."_".strtoupper($key)."'"; - $sql.= " AND entity = ".$entity; + $sql = "DELETE FROM ".MAIN_DB_PREFIX."const"; + $sql.= " WHERE ".$this->db->decrypt('name')." LIKE '".$this->const_name."_".strtoupper($key)."'"; + $sql.= " AND entity = ".$entity; - dol_syslog(get_class($this)."::delete_const_".$key."", LOG_DEBUG); - if (! $this->db->query($sql)) - { - $this->error=$this->db->lasterror(); - $err++; - } - } - } - return $err; + dol_syslog(get_class($this)."::delete_const_".$key."", LOG_DEBUG); + if (! $this->db->query($sql)) + { + $this->error=$this->db->lasterror(); + $err++; + } + } + } + return $err; } } diff --git a/htdocs/install/etape1.php b/htdocs/install/etape1.php index 50d5ee27b55..7b39fa06cf7 100644 --- a/htdocs/install/etape1.php +++ b/htdocs/install/etape1.php @@ -86,12 +86,15 @@ if (! is_writable($conffile)) // Check parameters +$is_sqlite = false; if (empty($db_type)) { print '
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("DatabaseType")).'
'; $error++; +} else { + $is_sqlite = ($db_type === 'sqlite' || $db_type === 'sqlite3' ); } -if (empty($db_host)) +if (empty($db_host) && ! $is_sqlite) { print '
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Server")).'
'; $error++; @@ -101,7 +104,7 @@ if (empty($db_name)) print '
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("DatabaseName")).'
'; $error++; } -if (empty($db_user)) +if (empty($db_user) && ! $is_sqlite) { print '
'.$langs->trans("ErrorFieldRequired",$langs->transnoentities("Login")).'
'; $error++; diff --git a/index.php b/index.php deleted file mode 100644 index e4341bb53ec..00000000000 --- a/index.php +++ /dev/null @@ -1,2 +0,0 @@ -
'.$langs->trans("TableName").'Rows'.$langs->trans("NbOfRecord").'