30require_once DOL_DOCUMENT_ROOT.
'/core/db/DoliDB.class.php';
54 const WEEK_MONDAY_FIRST = 1;
56 const WEEK_FIRST_WEEKDAY = 4;
71 public function __construct(
$type, $host, $user, $pass, $name =
'', $port = 0, $forcenew =
false)
76 if (!empty(
$conf->db->character_set)) {
77 $this->forcecharset =
$conf->db->character_set;
79 if (!empty(
$conf->db->dolibarr_main_db_collation)) {
80 $this->forcecollate =
$conf->db->dolibarr_main_db_collation;
83 $this->database_user = $user;
84 $this->database_host = $host;
85 $this->database_port = $port;
87 $this->transaction_opened = 0;
111 $this->db = $this->
connect($host, $user, $pass, $name, $port);
114 $this->connected =
true;
116 $this->database_selected =
true;
117 $this->database_name = $name;
130 $this->connected =
false;
132 $this->database_selected =
false;
133 $this->database_name =
'';
135 dol_syslog(get_class($this).
"::DoliDBSqlite3 : Error Connect ".$this->
error, LOG_ERR);
150 if (preg_match(
'/^--\s\$Id/i', $line)) {
154 if (preg_match(
'/^#/i', $line) || preg_match(
'/^$/i', $line) || preg_match(
'/^--/i', $line)) {
158 if (
$type ==
'auto') {
159 if (preg_match(
'/ALTER TABLE/i', $line)) {
161 } elseif (preg_match(
'/CREATE TABLE/i', $line)) {
163 } elseif (preg_match(
'/DROP TABLE/i', $line)) {
168 if (
$type ==
'dml') {
169 $line = preg_replace(
'/\s/',
' ', $line);
172 if (preg_match(
'/(ISAM|innodb)/i', $line)) {
173 $line = preg_replace(
'/\)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i',
');', $line);
174 $line = preg_replace(
'/\)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i',
');', $line);
175 $line = preg_replace(
'/,$/',
'', $line);
179 if (preg_match(
'/[\s\t\(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
180 $newline = preg_replace(
'/([\s\t\(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i',
'\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
186 $line = str_replace(
'tinyint',
'smallint', $line);
189 $line = preg_replace(
'/(int\w+|smallint)\s+unsigned/i',
'\\1', $line);
192 $line = preg_replace(
'/\w*blob/i',
'text', $line);
195 $line = preg_replace(
'/tinytext/i',
'text', $line);
196 $line = preg_replace(
'/mediumtext/i',
'text', $line);
200 $line = preg_replace(
'/datetime not null/i',
'datetime', $line);
201 $line = preg_replace(
'/datetime/i',
'timestamp', $line);
204 $line = preg_replace(
'/^double/i',
'numeric', $line);
205 $line = preg_replace(
'/(\s*)double/i',
'\\1numeric', $line);
207 $line = preg_replace(
'/^float/i',
'numeric', $line);
208 $line = preg_replace(
'/(\s*)float/i',
'\\1numeric', $line);
211 if (preg_match(
'/unique index\s*\((\w+\s*,\s*\w+)\)/i', $line)) {
212 $line = preg_replace(
'/unique index\s*\((\w+\s*,\s*\w+)\)/i',
'UNIQUE\(\\1\)', $line);
216 $line = preg_replace(
'/AFTER [a-z0-9_]+/i',
'', $line);
219 $line = preg_replace(
'/ALTER TABLE [a-z0-9_]+ DROP INDEX/i',
'DROP INDEX', $line);
222 if (preg_match(
'/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
223 $line =
"-- ".$line.
" replaced by --\n";
224 $line .=
"ALTER TABLE ".$reg[1].
" RENAME COLUMN ".$reg[2].
" TO ".$reg[3];
228 if (preg_match(
'/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
229 $line =
"-- ".$line.
" replaced by --\n";
231 $newreg3 = preg_replace(
'/ DEFAULT NULL/i',
'', $newreg3);
232 $newreg3 = preg_replace(
'/ NOT NULL/i',
'', $newreg3);
233 $newreg3 = preg_replace(
'/ NULL/i',
'', $newreg3);
234 $newreg3 = preg_replace(
'/ DEFAULT 0/i',
'', $newreg3);
235 $newreg3 = preg_replace(
'/ DEFAULT \'[0-9a-zA-Z_@]*\'/i',
'', $newreg3);
236 $line .=
"ALTER TABLE ".$reg[1].
" ALTER COLUMN ".$reg[2].
" TYPE ".$newreg3;
242 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\((.*)$/i', $line, $reg)) {
243 $line =
"-- ".$line.
" replaced by --\n";
244 $line .=
"CREATE UNIQUE INDEX ".$reg[2].
" ON ".$reg[1].
"(".$reg[3];
249 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
250 $line =
"-- ".$line.
" replaced by --\n";
251 $line .=
"ALTER TABLE ".$reg[1].
" DROP CONSTRAINT ".$reg[2];
256 if (preg_match(
'/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\(([\w,\s]+)\)/i', $line, $reg)) {
257 $fieldlist = $reg[4];
259 $tablename = $reg[1];
260 $line =
"-- ".$line.
" replaced by --\n";
261 $line .=
"CREATE ".(preg_match(
'/UNIQUE/', $reg[2]) ?
'UNIQUE ' :
'').
"INDEX ".$idxname.
" ON ".$tablename.
" (".$fieldlist.
")";
263 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)) {
265 dol_syslog(get_class().
'::query line emptied');
276 if (preg_match(
'/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
277 if ($reg[1] == $reg[2]) {
278 $line = preg_replace(
'/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i',
'DELETE FROM \\1 USING \\3', $line);
283 $line = preg_replace(
'/FROM\s*\((([a-z_]+)\s+as\s+([a-z_]+)\s*)\)/i',
'FROM \\1', $line);
287 $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);
291 $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);
310 dol_syslog(get_class($this).
"::select_db database=".$database, LOG_DEBUG);
329 public function connect($host, $login, $passwd, $name, $port = 0, $forcenew =
false)
331 global $main_data_dir;
333 dol_syslog(get_class($this).
"::connect name=".$name, LOG_DEBUG);
335 $dir = $main_data_dir;
337 $dir = DOL_DATA_ROOT;
341 $database_name = $dir.
'/database_'.$name.
'.sdb';
345 $this->db =
new SQLite3($database_name);
347 }
catch (Throwable $e) {
348 $this->
error = self::LABEL.
' '.$e->getMessage().
' current dir='.$database_name;
364 $tmp = $this->db->version();
365 return $tmp[
'versionString'];
375 return 'sqlite3 php driver';
388 if ($this->transaction_opened > 0) {
389 dol_syslog(get_class($this).
"::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
391 $this->connected =
false;
409 public function query($query, $usesavepoint = 0,
$type =
'auto', $result_mode = 0)
411 global
$conf, $dolibarr_main_db_readonly;
415 $query = trim($query);
421 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)) {
426 $foreignFields = $reg[5];
427 $foreignTable = $reg[4];
428 $localfields = $reg[3];
429 $constraintname = trim($reg[2]);
430 $tablename = trim($reg[1]);
432 $descTable = $this->db->querySingle(
"SELECT sql FROM sqlite_master WHERE name='".$this->
escape($tablename).
"'");
435 $this->
query(
"ALTER TABLE ".$tablename.
" RENAME TO tmp_".$tablename);
440 $descTable = substr($descTable, 0, strlen($descTable) - 1);
441 $descTable .=
", CONSTRAINT ".$constraintname.
" FOREIGN KEY (".$localfields.
") REFERENCES ".$foreignTable.
"(".$foreignFields.
")";
447 $this->
query($descTable);
450 $this->
query(
"INSERT INTO ".$tablename.
" SELECT * FROM tmp_".$tablename);
453 $this->
query(
"DROP TABLE tmp_".$tablename);
462 if (!in_array($query, array(
'BEGIN',
'COMMIT',
'ROLLBACK'))) {
463 $SYSLOG_SQL_LIMIT = 10000;
464 dol_syslog(
'sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
470 if (!empty($dolibarr_main_db_readonly)) {
471 if (preg_match(
'/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
472 $this->
lasterror =
'Application in read-only mode';
482 $ret = $this->db->query($query);
484 $this->queryString = $query;
486 }
catch (Throwable $e) {
487 $this->
error = $this->db->lastErrorMsg();
490 if (!preg_match(
"/^COMMIT/i", $query) && !preg_match(
"/^ROLLBACK/i", $query)) {
492 if (!is_object($ret) || $this->
error) {
497 dol_syslog(get_class($this).
"::query SQL Error query: ".$query, LOG_ERR);
499 $errormsg = get_class($this).
"::query SQL Error message: ".$this->lasterror;
501 if (preg_match(
'/[0-9]/', $this->
lasterrno)) {
502 $errormsg .=
' ('.$this->lasterrno.
')';
506 dol_syslog(get_class($this).
"::query SQL Error query: ".$query, LOG_ERR);
508 dol_syslog(get_class($this).
"::query SQL Error message: ".$errormsg, LOG_ERR);
511 $this->_results = $ret;
528 if (!is_object($resultset)) {
529 $resultset = $this->_results;
532 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
534 return (
object) $ret;
551 if (!is_object($resultset)) {
552 $resultset = $this->_results;
555 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
570 if (!is_bool($resultset)) {
571 if (!is_object($resultset)) {
572 $resultset = $this->_results;
574 return $resultset->fetchArray(SQLITE3_NUM);
594 if (!is_object($resultset)) {
595 $resultset = $this->_results;
598 if (preg_match(
"/^SELECT/i", $resultset->queryString)) {
600 return $this->db->querySingle(
"SELECT count(*) FROM (".$resultset->queryString.
") q");
618 if (!is_object($resultset)) {
619 $resultset = $this->_results;
621 if (preg_match(
"/^SELECT/i", $this->queryString)) {
625 return $this->db->changes();
635 public function free($resultset =
null)
638 if (!is_object($resultset)) {
639 $resultset = $this->_results;
642 if ($resultset && is_object($resultset)) {
643 $resultset->finalize();
655 return SQLite3::escapeString((
string) $stringtoencode);
666 return str_replace(array(
'\\',
'_',
'%'), array(
'\\\\',
'\_',
'\%'), (
string) $stringtoencode);
676 if (!$this->connected) {
678 return 'DB_ERROR_FAILED_TO_CONNECT';
713 $errno = $this->db->lastErrorCode();
714 if ($errno ==
'HY000' || $errno == 0) {
715 if (preg_match(
'/table.*already exists/i', $this->
error)) {
716 return 'DB_ERROR_TABLE_ALREADY_EXISTS';
717 } elseif (preg_match(
'/index.*already exists/i', $this->
error)) {
718 return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
719 } elseif (preg_match(
'/syntax error/i', $this->
error)) {
720 return 'DB_ERROR_SYNTAX';
723 if ($errno ==
'23000') {
724 if (preg_match(
'/column.* not unique/i', $this->
error)) {
725 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
726 } elseif (preg_match(
'/PRIMARY KEY must be unique/i', $this->
error)) {
727 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
734 return ($errno ?
'DB_ERROR_'.$errno :
'0');
745 if (!$this->connected) {
747 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
764 return $this->db->lastInsertRowId();
775 public function encrypt($fieldorvalue, $withQuotes = 1)
780 $cryptType = (!empty(
$conf->db->dolibarr_main_db_encryption) ?
$conf->db->dolibarr_main_db_encryption : 0);
783 $cryptKey = (!empty(
$conf->db->dolibarr_main_db_cryptkey) ?
$conf->db->dolibarr_main_db_cryptkey :
'');
785 $escapedstringwithquotes = ($withQuotes ?
"'" :
"").$this->
escape($fieldorvalue).($withQuotes ?
"'" :
"");
787 if ($cryptType && !empty($cryptKey)) {
788 if ($cryptType == 2) {
789 $escapedstringwithquotes =
"AES_ENCRYPT(".$escapedstringwithquotes.
", '".$this->
escape($cryptKey).
"')";
790 } elseif ($cryptType == 1) {
791 $escapedstringwithquotes =
"DES_ENCRYPT(".$escapedstringwithquotes.
", '".$this->
escape($cryptKey).
"')";
795 return $escapedstringwithquotes;
809 $cryptType = (
$conf->db->dolibarr_main_db_encryption ?
$conf->db->dolibarr_main_db_encryption : 0);
812 $cryptKey = (!empty(
$conf->db->dolibarr_main_db_cryptkey) ?
$conf->db->dolibarr_main_db_cryptkey :
'');
816 if ($cryptType && !empty($cryptKey)) {
817 if ($cryptType == 2) {
818 $return =
'AES_DECRYPT('.$value.
',\''.$cryptKey.
'\')
';
819 } elseif ($cryptType == 1) {
820 $return = 'DES_DECRYPT(
'.$value.',\
''.$cryptKey.
'\')
';
828 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
834 public function DDLGetConnectId()
841 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
853 public function DDLCreateDb($database, $charset = '
', $collation = '', $owner = '')
856 if (empty($charset)) {
857 $charset = $this->forcecharset;
859 if (empty($collation)) {
860 $collation = $this->forcecollate;
863 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
864 $sql = "CREATE DATABASE ".$this->sanitize($database);
865 $sql .= " DEFAULT CHARACTER SET ".$this->sanitize($charset)." DEFAULT COLLATE ".$this->sanitize($collation);
867 dol_syslog($sql, LOG_DEBUG);
868 $ret = $this->query($sql);
873 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
881 public function DDLListTables($database, $table = '
')
884 $listtables = array();
888 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i
', '', $table);
890 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
892 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $database); // @phan-suppress-current-line SqlInjection
894 $sql = "SHOW TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
896 $result = $this->query($sql);
898 while ($row = $this->fetch_row($result)) {
899 $listtables[] = $row[0];
905 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
913 public function DDLListTablesFull($database, $table = '
')
916 $listtables = array();
920 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i
', '', $table);
922 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
924 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $database); // @phan-suppress-current-line SqlInjection
926 $sql = "SHOW FULL TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
928 $result = $this->query($sql);
930 while ($row = $this->fetch_row($result)) {
931 $listtables[] = $row;
937 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
946 public function DDLInfoTable($table)
949 $infotables = array();
951 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $table);
953 $sql = "SHOW FULL COLUMNS FROM ".$sanitizedtmptable.";";
955 dol_syslog($sql, LOG_DEBUG);
956 $result = $this->query($sql);
958 while ($row = $this->fetch_row($result)) {
959 $infotables[] = $row;
965 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
978 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
981 // @TODO: $fulltext_keys parameter is unused
986 // Keys found into the array $fields: type,value,attribute,null,default,extra
987 // ex. : $fields['rowid
'] = array(
988 // 'type'=>'int' or 'integer
',
990 // 'null'=>'not
null',
991 // 'extra
'=> 'auto_increment
'
993 $sql = "CREATE TABLE ".$this->sanitize($table)."(";
995 $sqlfields = array();
996 foreach ($fields as $field_name => $field_desc) {
997 $sqlfields[$i] = $this->sanitize($field_name)." ";
998 $sqlfields[$i] .= $this->sanitize($field_desc['type']);
999 if (!is_null($field_desc['value
']) && $field_desc['value
'] !== '') {
1000 $sqlfields[$i] .= "(".$this->sanitize($field_desc['value
']).")";
1002 if (!is_null($field_desc['attribute
']) && $field_desc['attribute
'] !== '') {
1003 $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute
']);
1005 if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
1006 if (in_array($field_desc['type'], array('tinyint
', 'smallint
', 'int', 'double'))) {
1007 $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
1008 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP
') {
1009 $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
1011 $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1014 if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
1015 $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1017 if (!is_null($field_desc['extra
']) && $field_desc['extra
'] !== '') {
1018 $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra
'], 0, 0, 1);
1022 if ($primary_key != "") {
1023 $sanitizedpk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1029 if (is_array($unique_keys)) {
1031 foreach ($unique_keys as $key => $value) {
1032 $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
1036 if (is_array($keys)) {
1038 foreach ($keys as $key => $value) {
1039 $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
1043 $sql .= implode(',
', $sqlfields);
1044 if ($primary_key != "") {
1045 $sql .= ",".$sanitizedpk;
1047 if ($unique_keys != "") {
1048 $sql .= ",".implode(',
', $sqluq);
1050 if (is_array($keys)) {
1051 $sql .= ",".implode(',
', $sqlk);
1054 //$sql .= " engine=".$this->sanitize($type);
1056 if (!$this->query($sql)) {
1063 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1070 public function DDLDropTable($table)
1073 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $table);
1075 $sql = "DROP TABLE ".$sanitizedtmptable;
1077 if (!$this->query($sql)) {
1084 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1092 public function DDLDescTable($table, $field = "")
1095 $sql = "DESC ".$this->sanitize($table)." ".$this->sanitize($field);
1097 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1098 $this->_results = $this->query($sql);
1099 return $this->_results;
1102 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1112 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1115 // keys looked up in the descriptions array (field_desc): type,value,attribute,null,default,extra
1116 // ex. : $field_desc = array('
type'=>'int','value
'=>'11
','null'=>'not
null','extra
'=> 'auto_increment
');
1117 $sql = "ALTER TABLE ".$this->sanitize($table)." ADD ".$this->sanitize($field_name)." ";
1119 if ($field_desc['type'] !== 'datetimegmt
') {
1120 $sql .= $this->sanitize($field_desc['type']);
1125 if (in_array($field_desc['type'], array('double', 'int', 'varchar
')) && array_key_exists('value
', $field_desc) && !empty($field_desc['value
'])) {
1126 $sql .= "(".$this->sanitize($field_desc['value
']).")";
1128 if (isset($field_desc['attribute
']) && preg_match("/^[^\s]/i", $field_desc['attribute
'])) {
1129 $sql .= " ".$this->sanitize($field_desc['attribute
']);
1131 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
1132 if ($field_desc['null'] == 'NOT NULL
') {
1133 $sql .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1135 $sql .= " ".$this->sanitize($field_desc['null']);
1138 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
1139 if (in_array($field_desc['type'], array('tinyint
', 'smallint
', 'int', 'double'))) {
1140 $sql .= " DEFAULT ".((float) $field_desc['default']);
1141 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP
') {
1142 $sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
1144 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1147 if (isset($field_desc['extra
']) && preg_match("/^[^\s]/i", $field_desc['extra
'])) {
1148 $sql .= " ".$this->sanitize($field_desc['extra
'], 0, 0, 1);
1150 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1152 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1153 if (!$this->query($sql)) {
1159 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1168 public function DDLUpdateField($table, $field_name, $field_desc)
1171 $sql = "ALTER TABLE ".$this->sanitize($table);
1172 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ";
1174 if ($field_desc['
type'] !== 'datetimegmt
') {
1175 $sql .= $this->sanitize($field_desc['type']);
1180 if (in_array($field_desc['type'], array('double', 'int', 'varchar
')) && array_key_exists('value
', $field_desc) && !empty($field_desc['value
'])) {
1181 $sql .= "(".$this->sanitize($field_desc['value
']).")";
1184 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1185 if (!$this->query($sql)) {
1191 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1199 public function DDLDropField($table, $field_name)
1202 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i
', '', $field_name);
1204 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1205 if (!$this->query($sql)) {
1206 $this->error = $this->lasterror();
1213 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1223 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1226 $sql = "INSERT INTO user ";
1227 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1228 $sql .= " VALUES ('
".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".$this->escape($dolibarr_main_db_pass)."')";
1229 $sql .= ",'Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
')";
1231 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1232 $resql = $this->query($sql);
1237 $sql = "INSERT INTO db ";
1238 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1239 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".$this->escape($dolibarr_main_db_user)."'";
1240 $sql .= ",'Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
','Y
')";
1242 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1243 $resql = $this->query($sql);
1248 $sql = "FLUSH Privileges";
1250 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1251 $resql = $this->query($sql);
1263 public function getDefaultCharacterSetDatabase()
1273 public function getListOfCharacterSet()
1277 $liste[$i]['charset
'] = 'UTF-8
';
1287 public function getDefaultCollationDatabase()
1297 public function getListOfCollation()
1301 $liste[$i]['collation
'] = 'UTF-8
';
1310 public function getPathOfDump()
1312 // FIXME: not for SQLite
1313 $fullpathofdump = '/pathtomysqldump/mysqldump
';
1315 $resql = $this->query("SHOW VARIABLES LIKE 'basedir
'");
1317 $liste = $this->fetch_array($resql);
1318 $basedir = $liste['Value
'];
1319 $fullpathofdump = $basedir.(preg_match('/\/$/
', $basedir) ? '' : '/
').'bin/mysqldump
';
1321 return $fullpathofdump;
1329 public function getPathOfRestore()
1331 // FIXME: not for SQLite
1332 $fullpathofimport = '/pathtomysql/mysql
';
1334 $resql = $this->query("SHOW VARIABLES LIKE 'basedir
'");
1336 $liste = $this->fetch_array($resql);
1337 $basedir = $liste['Value
'];
1338 $fullpathofimport = $basedir.(preg_match('/\/$/
', $basedir) ? '' : '/
').'bin/mysql
';
1340 return $fullpathofimport;
1349 public function getServerParametersValues($filter = '
')
1353 if (!isset($pragmas)) {
1354 // Define the list of pragmas used that return only a single value
1355 // independent of the database.
1356 // cf. http://www.sqlite.org/pragma.html
1358 'application_id
', 'auto_vacuum
', 'automatic_index
', 'busy_timeout
', 'cache_size
',
1359 'cache_spill
', 'case_sensitive_like
', 'checkpoint_fullsync
', 'collation_list
',
1360 'compile_options
', 'data_version
', /*'database_list
',*/
1361 'defer_foreign_keys
', 'encoding
', 'foreign_key_check
', 'freelist_count
',
1362 'full_column_names
', 'fullsync
', 'ingore_check_constraints
', 'integrity_check
',
1363 'journal_mode
', 'journal_size_limit
', 'legacy_file_format
', 'locking_mode
',
1364 'max_page_count
', 'page_count
', 'page_size
', 'parser_trace
',
1365 'query_only
', 'quick_check
', 'read_uncommitted
', 'recursive_triggers
',
1366 'reverse_unordered_selects
', 'schema_version
', 'user_version
',
1367 'secure_delete
', 'short_column_names
', 'shrink_memory
', 'soft_heap_limit
',
1368 'synchronous
', 'temp_store
', /*'temp_store_directory
',*/ 'threads
',
1369 'vdbe_addoptrace
', 'vdbe_debug
', 'vdbe_listing
', 'vdbe_trace
',
1370 'wal_autocheckpoint
',
1374 // TODO prendre en compte le filtre
1375 foreach ($pragmas as $var) {
1376 $sql = "PRAGMA $var"; // @phan-suppress-current-line SqlInjection
1377 $resql = $this->query($sql);
1379 $obj = $this->fetch_row($resql);
1380 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1381 $result[$var] = $obj[0];
1383 // TODO Retrieve the message
1384 $result[$var] = 'FAIL
';
1396 public function getServerStatusValues($filter = '
')
1402 $sql.=" LIKE '".$this->escape($filter)."'";
1404 $resql=$this->query($sql);
1407 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1425 private function addCustomFunction($name, $arg_count = -1)
1428 $newname = preg_replace('/_/
', '', $name);
1429 $localname = __CLASS__.'::db
'.$newname;
1430 $reflectClass = new ReflectionClass(__CLASS__);
1431 $reflectFunction = $reflectClass->getMethod('db
'.$newname);
1432 if ($arg_count < 0) {
1433 $arg_count = $reflectFunction->getNumberOfParameters();
1435 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1436 $this->error = "unable to create custom function '$name
'";
1448 public function prepare($sql)
1450 $sql = $this->convertSQLFromMysql($sql);
1452 dol_syslog(get_class($this)."::prepare sql=".$sql, LOG_DEBUG);
1455 $stmt = $this->db->prepare($sql);
1456 } catch (Throwable $e) {
1458 $this->error = $e->getMessage();
1460 if (!($stmt instanceof SQLite3Stmt)) {
1461 $this->lasterror = $this->error ? $this->error : $this->db->lastErrorMsg();
1462 $this->lastqueryerror = $sql;
1465 // Keep the query text so num_rows()/affected_rows() can tell a SELECT from the rest
1466 $this->queryString = $sql;
1480 public function execute($stmt, $params = array())
1482 if (!($stmt instanceof SQLite3Stmt)) {
1483 $this->lasterror = '
execute() called with an invalid statement';
1491 foreach (array_values($params) as $v) {
1492 if (is_int($v) || is_bool($v)) {
1493 $stmt->bindValue($i, (
int) $v, SQLITE3_INTEGER);
1494 } elseif (is_float($v)) {
1495 $stmt->bindValue($i, $v, SQLITE3_FLOAT);
1496 } elseif (is_null($v)) {
1497 $stmt->bindValue($i,
null, SQLITE3_NULL);
1499 $stmt->bindValue($i, (
string) $v, SQLITE3_TEXT);
1504 dol_syslog(get_class($this).
"::execute (".($i - 1).
" bound param(s))", LOG_DEBUG);
1507 $res = $stmt->execute();
1508 }
catch (Throwable $e) {
1510 $this->
error = $e->getMessage();
1512 if (!($res instanceof SQLite3Result)) {
1517 $this->_results = $res;
1519 return ($res->numColumns() > 0) ? $res :
true;
foreach( $object->fields as $key=> $val)
@phan-var-force array<string, array{label:string, data-html:string, disable?:int, css?...
$propal type
'integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter[:Sortfield]]]',...
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.
__construct($type, $host, $user, $pass, $name='', $port=0, $forcenew=false)
Constructor.
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.
execute($stmt, $params=array())
Execute a statement previously created with prepare().
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.
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.
const VERSIONMIN
Version min database.
connect($host, $login, $passwd, $name, $port=0, $forcenew=false)
Connection to server.
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.