30require_once DOL_DOCUMENT_ROOT.
'/core/db/DoliDB.class.php';
54 const WEEK_MONDAY_FIRST = 1;
56 const WEEK_FIRST_WEEKDAY = 4;
75 if (!empty(
$conf->db->character_set)) {
76 $this->forcecharset =
$conf->db->character_set;
78 if (!empty(
$conf->db->dolibarr_main_db_collation)) {
79 $this->forcecollate =
$conf->db->dolibarr_main_db_collation;
82 $this->database_user = $user;
83 $this->database_host = $host;
84 $this->database_port = $port;
86 $this->transaction_opened = 0;
110 $this->db = $this->
connect($host, $user, $pass, $name, $port);
113 $this->connected =
true;
115 $this->database_selected =
true;
116 $this->database_name = $name;
129 $this->connected =
false;
131 $this->database_selected =
false;
132 $this->database_name =
'';
134 dol_syslog(get_class($this).
"::DoliDBSqlite3 : Error Connect ".$this->
error, LOG_ERR);
149 if (preg_match(
'/^--\s\$Id/i', $line)) {
153 if (preg_match(
'/^#/i', $line) || preg_match(
'/^$/i', $line) || preg_match(
'/^--/i', $line)) {
157 if (
$type ==
'auto') {
158 if (preg_match(
'/ALTER TABLE/i', $line)) {
160 } elseif (preg_match(
'/CREATE TABLE/i', $line)) {
162 } elseif (preg_match(
'/DROP TABLE/i', $line)) {
167 if (
$type ==
'dml') {
168 $line = preg_replace(
'/\s/',
' ', $line);
171 if (preg_match(
'/(ISAM|innodb)/i', $line)) {
172 $line = preg_replace(
'/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i',
');', $line);
173 $line = preg_replace(
'/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i',
');', $line);
174 $line = preg_replace(
'/,$/',
'', $line);
178 if (preg_match(
'/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
179 $newline = preg_replace(
'/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i',
'\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
185 $line = str_replace(
'tinyint',
'smallint', $line);
188 $line = preg_replace(
'/(int\w+|smallint)\s+unsigned/i',
'\\1', $line);
191 $line = preg_replace(
'/\w*blob/i',
'text', $line);
194 $line = preg_replace(
'/tinytext/i',
'text', $line);
195 $line = preg_replace(
'/mediumtext/i',
'text', $line);
199 $line = preg_replace(
'/datetime not null/i',
'datetime', $line);
200 $line = preg_replace(
'/datetime/i',
'timestamp', $line);
203 $line = preg_replace(
'/^double/i',
'numeric', $line);
204 $line = preg_replace(
'/(\s*)double/i',
'\\1numeric', $line);
206 $line = preg_replace(
'/^float/i',
'numeric', $line);
207 $line = preg_replace(
'/(\s*)float/i',
'\\1numeric', $line);
210 if (preg_match(
'/unique index\s*\((\w+\s*,\s*\w+)\)/i', $line)) {
211 $line = preg_replace(
'/unique index\s*\((\w+\s*,\s*\w+)\)/i',
'UNIQUE\(\\1\)', $line);
215 $line = preg_replace(
'/AFTER [a-z0-9_]+/i',
'', $line);
218 $line = preg_replace(
'/ALTER TABLE [a-z0-9_]+ DROP INDEX/i',
'DROP INDEX', $line);
221 if (preg_match(
'/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
222 $line =
"-- ".$line.
" replaced by --\n";
223 $line .=
"ALTER TABLE ".$reg[1].
" RENAME COLUMN ".$reg[2].
" TO ".$reg[3];
227 if (preg_match(
'/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
228 $line =
"-- ".$line.
" replaced by --\n";
230 $newreg3 = preg_replace(
'/ DEFAULT NULL/i',
'', $newreg3);
231 $newreg3 = preg_replace(
'/ NOT NULL/i',
'', $newreg3);
232 $newreg3 = preg_replace(
'/ NULL/i',
'', $newreg3);
233 $newreg3 = preg_replace(
'/ DEFAULT 0/i',
'', $newreg3);
234 $newreg3 = preg_replace(
'/ DEFAULT \'[0-9a-zA-Z_@]*\'/i',
'', $newreg3);
235 $line .=
"ALTER TABLE ".$reg[1].
" ALTER COLUMN ".$reg[2].
" TYPE ".$newreg3;
241 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i', $line, $reg)) {
242 $line =
"-- ".$line.
" replaced by --\n";
243 $line .=
"CREATE UNIQUE INDEX ".$reg[2].
" ON ".$reg[1].
"(".$reg[3];
248 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
249 $line =
"-- ".$line.
" replaced by --\n";
250 $line .=
"ALTER TABLE ".$reg[1].
" DROP CONSTRAINT ".$reg[2];
255 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i', $line, $reg)) {
256 $fieldlist = $reg[4];
258 $tablename = $reg[1];
259 $line =
"-- ".$line.
" replaced by --\n";
260 $line .=
"CREATE ".(preg_match(
'/UNIQUE/', $reg[2]) ?
'UNIQUE ' :
'').
"INDEX ".$idxname.
" ON ".$tablename.
" (".$fieldlist.
")";
262 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)) {
264 dol_syslog(get_class().
'::query line emptied');
275 if (preg_match(
'/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
276 if ($reg[1] == $reg[2]) {
277 $line = preg_replace(
'/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i',
'DELETE FROM \\1 USING \\3', $line);
282 $line = preg_replace(
'/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i',
'FROM \\1', $line);
286 $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);
290 $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);
309 dol_syslog(get_class($this).
"::select_db database=".$database, LOG_DEBUG);
327 public function connect($host, $login, $passwd, $name, $port = 0)
329 global $main_data_dir;
331 dol_syslog(get_class($this).
"::connect name=".$name, LOG_DEBUG);
333 $dir = $main_data_dir;
335 $dir = DOL_DATA_ROOT;
339 $database_name = $dir.
'/database_'.$name.
'.sdb';
343 $this->db =
new SQLite3($database_name);
346 $this->
error = self::LABEL.
' '.$e->getMessage().
' current dir='.$database_name;
362 $tmp = $this->db->version();
363 return $tmp[
'versionString'];
373 return 'sqlite3 php driver';
386 if ($this->transaction_opened > 0) {
387 dol_syslog(get_class($this).
"::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
389 $this->connected =
false;
407 public function query($query, $usesavepoint = 0,
$type =
'auto', $result_mode = 0)
409 global
$conf, $dolibarr_main_db_readonly;
413 $query = trim($query);
419 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)) {
424 $foreignFields = $reg[5];
425 $foreignTable = $reg[4];
426 $localfields = $reg[3];
427 $constraintname = trim($reg[2]);
428 $tablename = trim($reg[1]);
430 $descTable = $this->db->querySingle(
"SELECT sql FROM sqlite_master WHERE name='".$this->
escape($tablename).
"'");
433 $this->
query(
"ALTER TABLE ".$tablename.
" RENAME TO tmp_".$tablename);
438 $descTable = substr($descTable, 0, strlen($descTable) - 1);
439 $descTable .=
", CONSTRAINT ".$constraintname.
" FOREIGN KEY (".$localfields.
") REFERENCES ".$foreignTable.
"(".$foreignFields.
")";
445 $this->
query($descTable);
448 $this->
query(
"INSERT INTO ".$tablename.
" SELECT * FROM tmp_".$tablename);
451 $this->
query(
"DROP TABLE tmp_".$tablename);
460 if (!in_array($query, array(
'BEGIN',
'COMMIT',
'ROLLBACK'))) {
461 $SYSLOG_SQL_LIMIT = 10000;
462 dol_syslog(
'sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
468 if (!empty($dolibarr_main_db_readonly)) {
469 if (preg_match(
'/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
470 $this->
lasterror =
'Application in read-only mode';
480 $ret = $this->db->query($query);
482 $this->queryString = $query;
485 $this->
error = $this->db->lastErrorMsg();
488 if (!preg_match(
"/^COMMIT/i", $query) && !preg_match(
"/^ROLLBACK/i", $query)) {
490 if (!is_object($ret) || $this->
error) {
495 dol_syslog(get_class($this).
"::query SQL Error query: ".$query, LOG_ERR);
497 $errormsg = get_class($this).
"::query SQL Error message: ".$this->lasterror;
499 if (preg_match(
'/[0-9]/', $this->
lasterrno)) {
500 $errormsg .=
' ('.$this->lasterrno.
')';
504 dol_syslog(get_class($this).
"::query SQL Error query: ".$query, LOG_ERR);
506 dol_syslog(get_class($this).
"::query SQL Error message: ".$errormsg, LOG_ERR);
509 $this->_results = $ret;
526 if (!is_object($resultset)) {
527 $resultset = $this->_results;
530 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
532 return (
object) $ret;
549 if (!is_object($resultset)) {
550 $resultset = $this->_results;
553 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
568 if (!is_bool($resultset)) {
569 if (!is_object($resultset)) {
570 $resultset = $this->_results;
572 return $resultset->fetchArray(SQLITE3_NUM);
592 if (!is_object($resultset)) {
593 $resultset = $this->_results;
596 if (preg_match(
"/^SELECT/i", $resultset->queryString)) {
598 return $this->db->querySingle(
"SELECT count(*) FROM (".$resultset->queryString.
") q");
616 if (!is_object($resultset)) {
617 $resultset = $this->_results;
619 if (preg_match(
"/^SELECT/i", $this->queryString)) {
623 return $this->db->changes();
633 public function free($resultset =
null)
636 if (!is_object($resultset)) {
637 $resultset = $this->_results;
640 if ($resultset && is_object($resultset)) {
641 $resultset->finalize();
653 return SQLite3::escapeString($stringtoencode);
664 return str_replace(array(
'\\',
'_',
'%'), array(
'\\\\',
'\_',
'\%'), (
string) $stringtoencode);
674 if (!$this->connected) {
676 return 'DB_ERROR_FAILED_TO_CONNECT';
711 $errno = $this->db->lastErrorCode();
712 if ($errno ==
'HY000' || $errno == 0) {
713 if (preg_match(
'/table.*already exists/i', $this->
error)) {
714 return 'DB_ERROR_TABLE_ALREADY_EXISTS';
715 } elseif (preg_match(
'/index.*already exists/i', $this->
error)) {
716 return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
717 } elseif (preg_match(
'/syntax error/i', $this->
error)) {
718 return 'DB_ERROR_SYNTAX';
721 if ($errno ==
'23000') {
722 if (preg_match(
'/column.* not unique/i', $this->
error)) {
723 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
724 } elseif (preg_match(
'/PRIMARY KEY must be unique/i', $this->
error)) {
725 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
732 return ($errno ?
'DB_ERROR_'.$errno :
'0');
743 if (!$this->connected) {
745 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
762 return $this->db->lastInsertRowId();
773 public function encrypt($fieldorvalue, $withQuotes = 1)
778 $cryptType = (!empty(
$conf->db->dolibarr_main_db_encryption) ?
$conf->db->dolibarr_main_db_encryption : 0);
781 $cryptKey = (!empty(
$conf->db->dolibarr_main_db_cryptkey) ?
$conf->db->dolibarr_main_db_cryptkey :
'');
783 $escapedstringwithquotes = ($withQuotes ?
"'" :
"").$this->
escape($fieldorvalue).($withQuotes ?
"'" :
"");
785 if ($cryptType && !empty($cryptKey)) {
786 if ($cryptType == 2) {
787 $escapedstringwithquotes =
"AES_ENCRYPT(".$escapedstringwithquotes.
", '".$this->
escape($cryptKey).
"')";
788 } elseif ($cryptType == 1) {
789 $escapedstringwithquotes =
"DES_ENCRYPT(".$escapedstringwithquotes.
", '".$this->
escape($cryptKey).
"')";
793 return $escapedstringwithquotes;
807 $cryptType = (
$conf->db->dolibarr_main_db_encryption ?
$conf->db->dolibarr_main_db_encryption : 0);
810 $cryptKey = (!empty(
$conf->db->dolibarr_main_db_cryptkey) ?
$conf->db->dolibarr_main_db_cryptkey :
'');
814 if ($cryptType && !empty($cryptKey)) {
815 if ($cryptType == 2) {
816 $return =
'AES_DECRYPT('.$value.
',\''.$cryptKey.
'\')
';
817 } elseif ($cryptType == 1) {
818 $return = 'DES_DECRYPT(
'.$value.',\
''.$cryptKey.
'\')
';
826 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
832 public function DDLGetConnectId()
839 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
851 public function DDLCreateDb($database, $charset = '
', $collation = '', $owner = '')
854 if (empty($charset)) {
855 $charset = $this->forcecharset;
857 if (empty($collation)) {
858 $collation = $this->forcecollate;
861 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
862 $sql = "CREATE DATABASE ".$this->escape($database);
863 $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
865 dol_syslog($sql, LOG_DEBUG);
866 $ret = $this->query($sql);
871 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
879 public function DDLListTables($database, $table = '
')
882 $listtables = array();
886 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i
', '', $table);
888 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
890 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $database);
892 $sql = "SHOW TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
894 $result = $this->query($sql);
896 while ($row = $this->fetch_row($result)) {
897 $listtables[] = $row[0];
903 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
911 public function DDLListTablesFull($database, $table = '
')
914 $listtables = array();
918 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i
', '', $table);
920 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
922 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $database);
924 $sql = "SHOW FULL TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
926 $result = $this->query($sql);
928 while ($row = $this->fetch_row($result)) {
929 $listtables[] = $row;
935 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
944 public function DDLInfoTable($table)
947 $infotables = array();
949 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $table);
951 $sql = "SHOW FULL COLUMNS FROM ".$sanitizedtmptable.";";
953 dol_syslog($sql, LOG_DEBUG);
954 $result = $this->query($sql);
956 while ($row = $this->fetch_row($result)) {
957 $infotables[] = $row;
963 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
976 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
979 // @TODO: $fulltext_keys parameter is unused
984 // Keys found into the array $fields: type,value,attribute,null,default,extra
985 // ex. : $fields['rowid
'] = array(
986 // 'type'=>'int' or 'integer
',
988 // 'null'=>'not
null',
989 // 'extra
'=> 'auto_increment
'
991 $sql = "CREATE TABLE ".$this->sanitize($table)."(";
993 $sqlfields = array();
994 foreach ($fields as $field_name => $field_desc) {
995 $sqlfields[$i] = $this->sanitize($field_name)." ";
996 $sqlfields[$i] .= $this->sanitize($field_desc['type']);
997 if (!is_null($field_desc['value
']) && $field_desc['value
'] !== '') {
998 $sqlfields[$i] .= "(".$this->sanitize($field_desc['value
']).")";
1000 if (!is_null($field_desc['attribute
']) && $field_desc['attribute
'] !== '') {
1001 $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute
']);
1003 if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
1004 if (in_array($field_desc['type'], array('tinyint
', 'smallint
', 'int', 'double'))) {
1005 $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
1006 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP
') {
1007 $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
1009 $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1012 if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
1013 $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1015 if (!is_null($field_desc['extra
']) && $field_desc['extra
'] !== '') {
1016 $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra
'], 0, 0, 1);
1020 if ($primary_key != "") {
1021 $sanitizedpk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1027 if (is_array($unique_keys)) {
1029 foreach ($unique_keys as $key => $value) {
1030 $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
1034 if (is_array($keys)) {
1036 foreach ($keys as $key => $value) {
1037 $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
1041 $sql .= implode(',
', $sqlfields);
1042 if ($primary_key != "") {
1043 $sql .= ",".$sanitizedpk;
1045 if ($unique_keys != "") {
1046 $sql .= ",".implode(',
', $sqluq);
1048 if (is_array($keys)) {
1049 $sql .= ",".implode(',
', $sqlk);
1052 //$sql .= " engine=".$this->sanitize($type);
1054 if (!$this->query($sql)) {
1061 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1068 public function DDLDropTable($table)
1071 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $table);
1073 $sql = "DROP TABLE ".$sanitizedtmptable;
1075 if (!$this->query($sql)) {
1082 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1090 public function DDLDescTable($table, $field = "")
1093 $sql = "DESC ".$this->sanitize($table)." ".$this->sanitize($field);
1095 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1096 $this->_results = $this->query($sql);
1097 return $this->_results;
1100 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1110 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1113 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1114 // ex. : $field_desc = array('
type'=>'int','value
'=>'11
','null'=>'not
null','extra
'=> 'auto_increment
');
1115 $sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." ";
1117 if ($field_desc['type'] !== 'datetimegmt
') {
1118 $sql .= $this->sanitize($field_desc['type']);
1123 if (in_array($field_desc['type'], array('double', 'int', 'varchar
')) && array_key_exists('value
', $field_desc) && !empty($field_desc['value
'])) {
1124 $sql .= "(".$this->sanitize($field_desc['value
']).")";
1126 if (isset($field_desc['attribute
']) && preg_match("/^[^\s]/i", $field_desc['attribute
'])) {
1127 $sql .= " ".$this->sanitize($field_desc['attribute
']);
1129 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
1130 if ($field_desc['null'] == 'NOT NULL
') {
1131 $sql .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1133 $sql .= " ".$this->sanitize($field_desc['null']);
1136 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
1137 if (in_array($field_desc['type'], array('tinyint
', 'smallint
', 'int', 'double'))) {
1138 $sql .= " DEFAULT ".((float) $field_desc['default']);
1139 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP
') {
1140 $sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
1142 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1145 if (isset($field_desc['extra
']) && preg_match("/^[^\s]/i", $field_desc['extra
'])) {
1146 $sql .= " ".$this->sanitize($field_desc['extra
'], 0, 0, 1);
1148 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1150 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1151 if (!$this->query($sql)) {
1157 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1166 public function DDLUpdateField($table, $field_name, $field_desc)
1169 $sql = "ALTER TABLE ".$this->sanitize($table);
1170 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ";
1172 if ($field_desc['
type'] !== 'datetimegmt
') {
1173 $sql .= $this->sanitize($field_desc['type']);
1178 if (in_array($field_desc['type'], array('double', 'int', 'varchar
')) && array_key_exists('value
', $field_desc) && !empty($field_desc['value
'])) {
1179 $sql .= "(".$this->sanitize($field_desc['value
']).")";
1182 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1183 if (!$this->query($sql)) {
1189 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1197 public function DDLDropField($table, $field_name)
1200 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $field_name);
1202 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1203 if (!$this->query($sql)) {
1204 $this->error = $this->lasterror();
1211 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1221 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1224 $sql = "INSERT INTO user ";
1225 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1226 $sql .= " VALUES ('
".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1227 $sql .= ",'Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
')";
1229 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1230 $resql = $this->query($sql);
1235 $sql = "INSERT INTO db ";
1236 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1237 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1238 $sql .= ",'Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
')";
1240 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1241 $resql = $this->query($sql);
1246 $sql = "FLUSH Privileges";
1248 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1249 $resql = $this->query($sql);
1261 public function getDefaultCharacterSetDatabase()
1271 public function getListOfCharacterSet()
1275 $liste[$i]['charset
'] = 'UTF-8
';
1285 public function getDefaultCollationDatabase()
1295 public function getListOfCollation()
1299 $liste[$i]['collation
'] = 'UTF-8
';
1308 public function getPathOfDump()
1310 // FIXME: not for SQLite
1311 $fullpathofdump = '/pathtomysqldump/mysqldump
';
1313 $resql = $this->query("SHOW VARIABLES LIKE 'basedir
'");
1315 $liste = $this->fetch_array($resql);
1316 $basedir = $liste['Value
'];
1317 $fullpathofdump = $basedir.(preg_match('/\/$/
', $basedir) ? '' : '/
').'bin/mysqldump
';
1319 return $fullpathofdump;
1327 public function getPathOfRestore()
1329 // FIXME: not for SQLite
1330 $fullpathofimport = '/pathtomysql/mysql
';
1332 $resql = $this->query("SHOW VARIABLES LIKE 'basedir
'");
1334 $liste = $this->fetch_array($resql);
1335 $basedir = $liste['Value
'];
1336 $fullpathofimport = $basedir.(preg_match('/\/$/
', $basedir) ? '' : '/
').'bin/mysql
';
1338 return $fullpathofimport;
1347 public function getServerParametersValues($filter = '
')
1351 if (!isset($pragmas)) {
1352 // Define the list of pragmas used that return only a single value
1353 // independent of the database.
1354 // cf. http://www.sqlite.org/pragma.html
1356 'application_id
', 'auto_vacuum
', 'automatic_index
', 'busy_timeout
', 'cache_size
',
1357 'cache_spill
', 'case_sensitive_like
', 'checkpoint_fullsync
', 'collation_list
',
1358 'compile_options
', 'data_version
', /*'database_list
',*/
1359 'defer_foreign_keys
', 'encoding
', 'foreign_key_check
', 'freelist_count
',
1360 'full_column_names
', 'fullsync
', 'ingore_check_constraints
', 'integrity_check
',
1361 'journal_mode
', 'journal_size_limit
', 'legacy_file_format
', 'locking_mode
',
1362 'max_page_count
', 'page_count
', 'page_size
', 'parser_trace
',
1363 'query_only
', 'quick_check
', 'read_uncommitted
', 'recursive_triggers
',
1364 'reverse_unordered_selects
', 'schema_version
', 'user_version
',
1365 'secure_delete
', 'short_column_names
', 'shrink_memory
', 'soft_heap_limit
',
1366 'synchronous
', 'temp_store
', /*'temp_store_directory
',*/ 'threads
',
1367 'vdbe_addoptrace
', 'vdbe_debug
', 'vdbe_listing
', 'vdbe_trace
',
1368 'wal_autocheckpoint
',
1372 // TODO prendre en compte le filtre
1373 foreach ($pragmas as $var) {
1374 $sql = "PRAGMA $var";
1375 $resql = $this->query($sql);
1377 $obj = $this->fetch_row($resql);
1378 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1379 $result[$var] = $obj[0];
1381 // TODO Retrieve the message
1382 $result[$var] = 'FAIL
';
1394 public function getServerStatusValues($filter = '
')
1400 $sql.=" LIKE '".$this->escape($filter)."'";
1402 $resql=$this->query($sql);
1405 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1423 private function addCustomFunction($name, $arg_count = -1)
1426 $newname = preg_replace('/_/
', '', $name);
1427 $localname = __CLASS__.'::db
'.$newname;
1428 $reflectClass = new ReflectionClass(__CLASS__);
1429 $reflectFunction = $reflectClass->getMethod('db
'.$newname);
1430 if ($arg_count < 0) {
1431 $arg_count = $reflectFunction->getNumberOfParameters();
1433 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1434 $this->error = "unable to create custom function '$name
'";
1439 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1443 * param int $year Year
1444 * param int $month Month
1445 * param int $day Day
1446 * return int Formatted date
1449 private static function calc_daynr($year, $month, $day)
1453 if ($y == 0 && $month == 0) {
1456 $num = (365 * $y + 31 * ($month - 1) + $day);
1460 $num -= floor(($month * 4 + 23) / 10);
1462 $temp = floor(($y / 100 + 1) * 3 / 4);
1463 return (int) ($num + floor($y / 4) - $temp);
1467 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1471 * param int $daynr ???
1472 * param bool $sunday_first_day_of_week ???
1476 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1479 $ret = (int) floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1484 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1488 * param int $year Year
1489 * return int Nb of days in year
1492 private static function calc_days_in_year($year)
1495 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1499 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1503 * param int $year Year
1504 * param int $month Month
1505 * param int $day Day
1506 * param int $week_behaviour Week behaviour, bit masks: WEEK_MONDAY_FIRST, WEEK_YEAR, WEEK_FIRST_WEEKDAY
1507 * param int $calc_year ??? Year where the week started
1508 * return int ??? Week number in year
1511 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1514 $daynr = self::calc_daynr($year, $month, $day);
1515 $first_daynr = self::calc_daynr($year, 1, 1);
1516 $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1517 $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1518 $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1520 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1523 if ($month == 1 && $day <= 7 - $weekday) {
1524 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1529 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1530 $weekday = ($weekday + 53 * 7 - $days) % 7;
1533 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1534 $days = $daynr - ($first_daynr + (7 - $weekday));
1536 $days = $daynr - ($first_daynr - $weekday);
1539 if ($week_year && $days >= 52 * 7) {
1540 $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1541 if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1546 return (int) floor($days / 7 + 1);
Class to manage Dolibarr database access.
lastqueryerror()
Return last query in error.
lasterror()
Return last error label.
lasterrno()
Return last error code.
lastquery()
Return last request executed with query()
Class to manage Dolibarr database access for a SQLite database.
fetch_object($resultset)
Returns the current line (as an object) for the resultset cursor.
escape($stringtoencode)
Escape a string to insert data.
fetch_array($resultset)
Return datas as an array.
query($query, $usesavepoint=0, $type='auto', $result_mode=0)
Execute a SQL request and return the resultset.
error()
Renvoie le texte de l'erreur mysql de l'operation precedente.
fetch_row($resultset)
Return datas as an array.
errno()
Renvoie le code erreur generique de l'operation precedente.
const LABEL
Database label.
close()
Close database connection.
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
encrypt($fieldorvalue, $withQuotes=1)
Encrypt sensitive data in database Warning: This function includes the escape and add the SQL simple ...
last_insert_id($tab, $fieldid='rowid')
Get last ID after an insert INSERT.
affected_rows($resultset)
Return number of lines for result of a SELECT.
decrypt($value)
Decrypt sensitive data in database.
getDriverInfo()
Return version of database client driver.
addCustomFunction($name, $arg_count=-1)
Add a custom function in the database engine (STORED PROCEDURE) Notes:
select_db($database)
Select a database.
connect($host, $login, $passwd, $name, $port=0)
Connection to server.
num_rows($resultset)
Return number of lines for result of a SELECT.
convertSQLFromMysql($line, $type='ddl')
Convert a SQL request in Mysql syntax to native syntax.
getVersion()
Return version of database server.
free($resultset=null)
Free last resultset used.
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
const VERSIONMIN
Version min database.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(preg_match('/(crypted|dolcrypt):/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...