dolibarr 24.0.0-beta
sqlite3.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001 Fabien Seisen <seisen@linuxfr.org>
3 * Copyright (C) 2002-2005 Rodolphe Quiedeville <rodolphe@quiedeville.org>
4 * Copyright (C) 2004-2011 Laurent Destailleur <eldy@users.sourceforge.net>
5 * Copyright (C) 2006 Andre Cianfarani <acianfa@free.fr>
6 * Copyright (C) 2005-2009 Regis Houssin <regis.houssin@inodbox.com>
7 * Copyright (C) 2015 Raphaël Doursenaud <rdoursenaud@gpcsolutions.fr>
8 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <https://www.gnu.org/licenses/>.
23 */
24
30require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
31
35class DoliDBSqlite3 extends DoliDB
36{
38 public $type = 'sqlite3';
40 const LABEL = 'Sqlite3';
42 const VERSIONMIN = '3.0.0';
43
47 private $_results;
48
52 private $queryString;
53
54 const WEEK_MONDAY_FIRST = 1;
55 const WEEK_YEAR = 2;
56 const WEEK_FIRST_WEEKDAY = 4;
57
58
70 public function __construct($type, $host, $user, $pass, $name = '', $port = 0) // @phpstan-ignore constructor.unusedParameter
71 {
72 global $conf;
73
74 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
75 if (!empty($conf->db->character_set)) {
76 $this->forcecharset = $conf->db->character_set;
77 }
78 if (!empty($conf->db->dolibarr_main_db_collation)) {
79 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
80 }
81
82 $this->database_user = $user;
83 $this->database_host = $host;
84 $this->database_port = $port;
85
86 $this->transaction_opened = 0;
87
88 //print "Name DB: $host,$user,$pass,$name<br>";
89
90 /*if (! function_exists("sqlite_query"))
91 {
92 $this->connected = false;
93 $this->ok = false;
94 $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
95 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);
96 return;
97 }*/
98
99 /*if (! $host)
100 {
101 $this->connected = false;
102 $this->ok = false;
103 $this->error=$langs->trans("ErrorWrongHostParameter");
104 dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
105 return;
106 }*/
107
108 // Essai connection serveur
109 // We do not try to connect to database, only to server. Connect to database is done later in constructor
110 $this->db = $this->connect($host, $user, $pass, $name, $port);
111
112 if ($this->db) {
113 $this->connected = true;
114 $this->ok = true;
115 $this->database_selected = true;
116 $this->database_name = $name;
117
118 $this->addCustomFunction('IF');
119 $this->addCustomFunction('MONTH');
120 $this->addCustomFunction('CURTIME');
121 $this->addCustomFunction('CURDATE');
122 $this->addCustomFunction('WEEK', 1);
123 $this->addCustomFunction('WEEK', 2);
124 $this->addCustomFunction('WEEKDAY');
125 $this->addCustomFunction('date_format');
126 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
127 } else {
128 // host, login ou password incorrect
129 $this->connected = false;
130 $this->ok = false;
131 $this->database_selected = false;
132 $this->database_name = '';
133 //$this->error=sqlite_connect_error();
134 dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error, LOG_ERR);
135 }
136 }
137
138
146 public function convertSQLFromMysql($line, $type = 'ddl')
147 {
148 // Removed empty line if this is a comment line for SVN tagging
149 if (preg_match('/^--\s\$Id/i', $line)) {
150 return '';
151 }
152 // Return line if this is a comment
153 if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
154 return $line;
155 }
156 if ($line != "") {
157 if ($type == 'auto') {
158 if (preg_match('/ALTER TABLE/i', $line)) {
159 $type = 'dml';
160 } elseif (preg_match('/CREATE TABLE/i', $line)) {
161 $type = 'dml';
162 } elseif (preg_match('/DROP TABLE/i', $line)) {
163 $type = 'dml';
164 }
165 }
166
167 if ($type == 'dml') {
168 $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
169
170 // we are inside create table statement so let's process datatypes
171 if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
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);
175 }
176
177 // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
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);
180 //$line = "-- ".$line." replaced by --\n".$newline;
181 $line = $newline;
182 }
183
184 // tinyint type conversion
185 $line = str_replace('tinyint', 'smallint', $line);
186
187 // nuke unsigned
188 $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
189
190 // blob -> text
191 $line = preg_replace('/\w*blob/i', 'text', $line);
192
193 // tinytext/mediumtext -> text
194 $line = preg_replace('/tinytext/i', 'text', $line);
195 $line = preg_replace('/mediumtext/i', 'text', $line);
196
197 // change not null datetime field to null valid ones
198 // (to support remapping of "zero time" to null
199 $line = preg_replace('/datetime not null/i', 'datetime', $line);
200 $line = preg_replace('/datetime/i', 'timestamp', $line);
201
202 // double -> numeric
203 $line = preg_replace('/^double/i', 'numeric', $line);
204 $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
205 // float -> numeric
206 $line = preg_replace('/^float/i', 'numeric', $line);
207 $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
208
209 // unique index(field1,field2)
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);
212 }
213
214 // We remove end of requests "AFTER fieldxxx"
215 $line = preg_replace('/AFTER [a-z0-9_]+/i', '', $line);
216
217 // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
218 $line = preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i', 'DROP INDEX', $line);
219
220 // Translate order to rename fields
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];
224 }
225
226 // Translate order to modify field format
227 if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
228 $line = "-- ".$line." replaced by --\n";
229 $newreg3 = $reg[3];
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;
236 // TODO Add alter to set default value or null/not null if there is this in $reg[3]
237 }
238
239 // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
240 // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
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];
244 }
245
246 // Translate order to drop foreign keys
247 // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
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];
251 }
252
253 // alter table add [unique] [index] (field1, field2 ...)
254 // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
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];
257 $idxname = $reg[3];
258 $tablename = $reg[1];
259 $line = "-- ".$line." replaced by --\n";
260 $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
261 }
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)) {
263 // Constraints are not yet created
264 dol_syslog(get_class().'::query line emptied');
265 $line = 'SELECT 0;';
266 }
267
268 //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
269 //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
270 //}
271 }
272
273 // Delete using criteria on other table must not declare twice the deleted table
274 // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
275 if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
276 if ($reg[1] == $reg[2]) { // If same table, we remove second one
277 $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
278 }
279 }
280
281 // Remove () in the tables in FROM if one table
282 $line = preg_replace('/FROM\s*\‍((([a-z_]+)\s+as\s+([a-z_]+)\s*)\‍)/i', 'FROM \\1', $line);
283 //print $line."\n";
284
285 // Remove () in the tables in FROM if two table
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);
287 //print $line."\n";
288
289 // Remove () in the tables in FROM if two table
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);
291 //print $line."\n";
292
293 //print "type=".$type." newline=".$line."<br>\n";
294 }
295
296 return $line;
297 }
298
299 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
306 public function select_db($database)
307 {
308 // phpcs:enable
309 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
310 // sqlite_select_db() does not exist
311 //return sqlite_select_db($this->db,$database);
312 return true;
313 }
314
315
327 public function connect($host, $login, $passwd, $name, $port = 0)
328 {
329 global $main_data_dir;
330
331 dol_syslog(get_class($this)."::connect name=".$name, LOG_DEBUG);
332
333 $dir = $main_data_dir;
334 if (empty($dir)) {
335 $dir = DOL_DATA_ROOT;
336 }
337 // With sqlite, port must be in connect parameters
338 //if (! $newport) $newport=3306;
339 $database_name = $dir.'/database_'.$name.'.sdb';
340 try {
341 /*** connect to SQLite database ***/
342 //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
343 $this->db = new SQLite3($database_name);
344 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
345 } catch (Exception $e) {
346 $this->error = self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
347 return false;
348 }
349
350 //print "Result of connect function: ".$this->db;
351 return $this->db;
352 }
353
354
360 public function getVersion()
361 {
362 $tmp = $this->db->version();
363 return $tmp['versionString'];
364 }
365
371 public function getDriverInfo()
372 {
373 return 'sqlite3 php driver';
374 }
375
376
383 public function close()
384 {
385 if ($this->db) {
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);
388 }
389 $this->connected = false;
390 $this->db->close();
391 unset($this->db); // Clean this->db
392 return true;
393 }
394 return false;
395 }
396
407 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
408 {
409 global $conf, $dolibarr_main_db_readonly;
410
411 $ret = false;
412
413 $query = trim($query);
414
415 $this->error = '';
416
417 // Convert MySQL syntax to SQLite syntax
418 $reg = array();
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)) {
420 // Adding a foreign key to the table
421 // table replacement procedure to add the constraint
422 // Example : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
423 // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
424 $foreignFields = $reg[5];
425 $foreignTable = $reg[4];
426 $localfields = $reg[3];
427 $constraintname = trim($reg[2]);
428 $tablename = trim($reg[1]);
429
430 $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='".$this->escape($tablename)."'");
431
432 // 1- Rename the table to a temporary name
433 $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
434
435 // 2- Recreate the table with the new constraint
436
437 // Adjust the SQL request to add the constraint
438 $descTable = substr($descTable, 0, strlen($descTable) - 1);
439 $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
440
441 // Add closing parenthesis for SQL query
442 $descTable .= ')';
443
444 // Perform query to create the table
445 $this->query($descTable);
446
447 // 3- Copy the data from the temporary table (before adding constraint)
448 $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
449
450 // 4- Delete the original (now temporary) table
451 $this->query("DROP TABLE tmp_".$tablename);
452
453 // dummy statement
454 $query = "SELECT 0";
455 } else {
456 $query = $this->convertSQLFromMysql($query, $type);
457 }
458 //print "After convertSQLFromMysql:\n".$query."<br>\n";
459
460 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
461 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
462 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
463 }
464 if (empty($query)) {
465 return false; // Return false = error if empty request
466 }
467
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';
471 $this->lasterrno = 'APPREADONLY';
472 $this->lastquery = $query;
473 return false;
474 }
475 }
476
477 // Ordre SQL ne necessitant pas de connection a une base (example: CREATE DATABASE)
478 try {
479 //$ret = $this->db->exec($query);
480 $ret = $this->db->query($query); // $ret is a Sqlite3Result
481 if ($ret) {
482 $this->queryString = $query;
483 }
484 } catch (Exception $e) {
485 $this->error = $this->db->lastErrorMsg();
486 }
487
488 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
489 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
490 if (!is_object($ret) || $this->error) {
491 $this->lastqueryerror = $query;
492 $this->lasterror = $this->error();
493 $this->lasterrno = $this->errno();
494
495 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
496
497 $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
498
499 if (preg_match('/[0-9]/', $this->lasterrno)) {
500 $errormsg .= ' ('.$this->lasterrno.')';
501 }
502
503 if (getDolGlobalString('SYSLOG_LEVEL') < LOG_DEBUG) {
504 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
505 }
506 dol_syslog(get_class($this)."::query SQL Error message: ".$errormsg, LOG_ERR);
507 }
508 $this->lastquery = $query;
509 $this->_results = $ret;
510 }
511
512 return $ret;
513 }
514
515 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
522 public function fetch_object($resultset)
523 {
524 // phpcs:enable
525 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connection
526 if (!is_object($resultset)) {
527 $resultset = $this->_results;
528 }
529 //return $resultset->fetch(PDO::FETCH_OBJ);
530 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
531 if ($ret) {
532 return (object) $ret;
533 }
534 return false;
535 }
536
537
538 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
545 public function fetch_array($resultset)
546 {
547 // phpcs:enable
548 // If resultset not provided, we take the last used by connection
549 if (!is_object($resultset)) {
550 $resultset = $this->_results;
551 }
552 //return $resultset->fetch(PDO::FETCH_ASSOC);
553 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
554 return $ret;
555 }
556
557 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
564 public function fetch_row($resultset)
565 {
566 // phpcs:enable
567 // If resultset not provided, we take the last used by connection
568 if (!is_bool($resultset)) {
569 if (!is_object($resultset)) {
570 $resultset = $this->_results;
571 }
572 return $resultset->fetchArray(SQLITE3_NUM);
573 } else {
574 // If the cursor is a boolean, return 0
575 return 0;
576 }
577 }
578
579 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
587 public function num_rows($resultset)
588 {
589 // phpcs:enable
590
591 // If resultset not provided, we take the last used by connection
592 if (!is_object($resultset)) {
593 $resultset = $this->_results;
594 }
595 // Ignore Phan - queryString is added as dynamic property @phan-suppress-next-line PhanUndeclaredProperty
596 if (preg_match("/^SELECT/i", $resultset->queryString)) {
597 // Ignore Phan - queryString is added as dynamic property @phan-suppress-next-line PhanUndeclaredProperty
598 return $this->db->querySingle("SELECT count(*) FROM (".$resultset->queryString.") q");
599 }
600 return 0;
601 }
602
603 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
611 public function affected_rows($resultset)
612 {
613 // phpcs:enable
614
615 // If resultset not provided, we take the last used by connection
616 if (!is_object($resultset)) {
617 $resultset = $this->_results;
618 }
619 if (preg_match("/^SELECT/i", $this->queryString)) {
620 return $this->num_rows($resultset);
621 }
622 // mysql requires a base link for this function, unlike pgsql which takes a resultset
623 return $this->db->changes();
624 }
625
626
633 public function free($resultset = null)
634 {
635 // If resultset not provided, we take the last used by connection
636 if (!is_object($resultset)) {
637 $resultset = $this->_results;
638 }
639 // Si resultset en est un, on libere la memoire
640 if ($resultset && is_object($resultset)) {
641 $resultset->finalize();
642 }
643 }
644
651 public function escape($stringtoencode)
652 {
653 return SQLite3::escapeString($stringtoencode);
654 }
655
662 public function escapeforlike($stringtoencode)
663 {
664 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
665 }
666
672 public function errno()
673 {
674 if (!$this->connected) {
675 // Si il y a eu echec de connection, $this->db n'est pas valide.
676 return 'DB_ERROR_FAILED_TO_CONNECT';
677 } else {
678 // Constants to convert error code to a generic Dolibarr error code
679 /*$errorcode_map = array(
680 1004 => 'DB_ERROR_CANNOT_CREATE',
681 1005 => 'DB_ERROR_CANNOT_CREATE',
682 1006 => 'DB_ERROR_CANNOT_CREATE',
683 1007 => 'DB_ERROR_ALREADY_EXISTS',
684 1008 => 'DB_ERROR_CANNOT_DROP',
685 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
686 1044 => 'DB_ERROR_ACCESSDENIED',
687 1046 => 'DB_ERROR_NODBSELECTED',
688 1048 => 'DB_ERROR_CONSTRAINT',
689 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
690 1051 => 'DB_ERROR_NOSUCHTABLE',
691 1054 => 'DB_ERROR_NOSUCHFIELD',
692 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
693 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
694 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
695 1064 => 'DB_ERROR_SYNTAX',
696 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
697 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
698 1091 => 'DB_ERROR_NOSUCHFIELD',
699 1100 => 'DB_ERROR_NOT_LOCKED',
700 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
701 1146 => 'DB_ERROR_NOSUCHTABLE',
702 1216 => 'DB_ERROR_NO_PARENT',
703 1217 => 'DB_ERROR_CHILD_EXISTS',
704 1451 => 'DB_ERROR_CHILD_EXISTS'
705 );
706
707 if (isset($errorcode_map[$this->db->errorCode()]))
708 {
709 return $errorcode_map[$this->db->errorCode()];
710 }*/
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';
719 }
720 }
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';
726 }
727 }
728 if ($errno > 1) {
729 // TODO Voir la liste des messages d'erreur
730 }
731
732 return ($errno ? 'DB_ERROR_'.$errno : '0');
733 }
734 }
735
741 public function error()
742 {
743 if (!$this->connected) {
744 // Si il y a eu echec de connection, $this->db n'est pas valide pour sqlite_error.
745 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
746 } else {
747 return $this->error;
748 }
749 }
750
751 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
759 public function last_insert_id($tab, $fieldid = 'rowid')
760 {
761 // phpcs:enable
762 return $this->db->lastInsertRowId();
763 }
764
773 public function encrypt($fieldorvalue, $withQuotes = 1)
774 {
775 global $conf;
776
777 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
778 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
779
780 //Encryption key
781 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
782
783 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
784
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)."')";
790 }
791 }
792
793 return $escapedstringwithquotes;
794 }
795
802 public function decrypt($value)
803 {
804 global $conf;
805
806 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
807 $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
808
809 //Encryption key
810 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
811
812 $return = $value;
813
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.'\')';
819 }
820 }
821
822 return $return;
823 }
824
825
826 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
832 public function DDLGetConnectId()
833 {
834 // phpcs:enable
835 return '?';
836 }
837
838
839 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
851 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
852 {
853 // phpcs:enable
854 if (empty($charset)) {
855 $charset = $this->forcecharset;
856 }
857 if (empty($collation)) {
858 $collation = $this->forcecollate;
859 }
860
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);
864
865 dol_syslog($sql, LOG_DEBUG);
866 $ret = $this->query($sql);
867
868 return $ret;
869 }
870
871 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
879 public function DDLListTables($database, $table = '')
880 {
881 // phpcs:enable
882 $listtables = array();
883
884 $sanitizedlike = '';
885 if ($table) {
886 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
887
888 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
889 }
890 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
891
892 $sql = "SHOW TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
893 //print $sql;
894 $result = $this->query($sql);
895 if ($result) {
896 while ($row = $this->fetch_row($result)) {
897 $listtables[] = $row[0];
898 }
899 }
900 return $listtables;
901 }
902
903 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
911 public function DDLListTablesFull($database, $table = '')
912 {
913 // phpcs:enable
914 $listtables = array();
915
916 $sanitizedlike = '';
917 if ($table) {
918 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
919
920 $sanitizedlike = "LIKE '".$this->escape($tmptable)."'";
921 }
922 $sanitizedtmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
923
924 $sql = "SHOW FULL TABLES FROM ".$sanitizedtmpdatabase." ".$sanitizedlike.";";
925 //print $sql;
926 $result = $this->query($sql);
927 if ($result) {
928 while ($row = $this->fetch_row($result)) {
929 $listtables[] = $row;
930 }
931 }
932 return $listtables;
933 }
934
935 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
944 public function DDLInfoTable($table)
945 {
946 // phpcs:enable
947 $infotables = array();
948
949 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
950
951 $sql = "SHOW FULL COLUMNS FROM ".$sanitizedtmptable.";";
952
953 dol_syslog($sql, LOG_DEBUG);
954 $result = $this->query($sql);
955 if ($result) {
956 while ($row = $this->fetch_row($result)) {
957 $infotables[] = $row;
958 }
959 }
960 return $infotables;
961 }
962
963 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
976 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
977 {
978 // phpcs:enable
979 // @TODO: $fulltext_keys parameter is unused
980
981 $sqlk = array();
982 $sqluq = array();
983
984 // Keys found into the array $fields: type,value,attribute,null,default,extra
985 // ex. : $fields['rowid'] = array(
986 // 'type'=>'int' or 'integer',
987 // 'value'=>'11',
988 // 'null'=>'not null',
989 // 'extra'=> 'auto_increment'
990 // );
991 $sql = "CREATE TABLE ".$this->sanitize($table)."(";
992 $i = 0;
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']).")";
999 }
1000 if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
1001 $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
1002 }
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']);
1008 } else {
1009 $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1010 }
1011 }
1012 if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
1013 $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1014 }
1015 if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
1016 $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1017 }
1018 $i++;
1019 }
1020 if ($primary_key != "") {
1021 $sanitizedpk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1022 } else {
1023 $sanitizedpk = "";
1024 }
1025
1026
1027 if (is_array($unique_keys)) {
1028 $i = 0;
1029 foreach ($unique_keys as $key => $value) {
1030 $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
1031 $i++;
1032 }
1033 }
1034 if (is_array($keys)) {
1035 $i = 0;
1036 foreach ($keys as $key => $value) {
1037 $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
1038 $i++;
1039 }
1040 }
1041 $sql .= implode(',', $sqlfields);
1042 if ($primary_key != "") {
1043 $sql .= ",".$sanitizedpk;
1044 }
1045 if ($unique_keys != "") {
1046 $sql .= ",".implode(',', $sqluq);
1047 }
1048 if (is_array($keys)) {
1049 $sql .= ",".implode(',', $sqlk);
1050 }
1051 $sql .= ")";
1052 //$sql .= " engine=".$this->sanitize($type);
1053
1054 if (!$this->query($sql)) {
1055 return -1;
1056 } else {
1057 return 1;
1058 }
1059 }
1060
1061 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1068 public function DDLDropTable($table)
1069 {
1070 // phpcs:enable
1071 $sanitizedtmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1072
1073 $sql = "DROP TABLE ".$sanitizedtmptable;
1074
1075 if (!$this->query($sql)) {
1076 return -1;
1077 } else {
1078 return 1;
1079 }
1080 }
1081
1082 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1090 public function DDLDescTable($table, $field = "")
1091 {
1092 // phpcs:enable
1093 $sql = "DESC ".$this->sanitize($table)." ".$this->sanitize($field);
1094
1095 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1096 $this->_results = $this->query($sql);
1097 return $this->_results;
1098 }
1099
1100 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1110 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1111 {
1112 // phpcs:enable
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)." ";
1116
1117 if ($field_desc['type'] !== 'datetimegmt') {
1118 $sql .= $this->sanitize($field_desc['type']);
1119 } else {
1120 $sql .= 'datetime';
1121 }
1122
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']).")";
1125 }
1126 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1127 $sql .= " ".$this->sanitize($field_desc['attribute']);
1128 }
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);
1132 } else {
1133 $sql .= " ".$this->sanitize($field_desc['null']);
1134 }
1135 }
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']);
1141 } else {
1142 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1143 }
1144 }
1145 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
1146 $sql .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1147 }
1148 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1149
1150 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1151 if (!$this->query($sql)) {
1152 return -1;
1153 }
1154 return 1;
1155 }
1156
1157 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1166 public function DDLUpdateField($table, $field_name, $field_desc)
1167 {
1168 // phpcs:enable
1169 $sql = "ALTER TABLE ".$this->sanitize($table);
1170 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ";
1171
1172 if ($field_desc['type'] !== 'datetimegmt') {
1173 $sql .= $this->sanitize($field_desc['type']);
1174 } else {
1175 $sql .= 'datetime';
1176 }
1177
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']).")";
1180 }
1181
1182 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1183 if (!$this->query($sql)) {
1184 return -1;
1185 }
1186 return 1;
1187 }
1188
1189 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1197 public function DDLDropField($table, $field_name)
1198 {
1199 // phpcs:enable
1200 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1201
1202 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1203 if (!$this->query($sql)) {
1204 $this->error = $this->lasterror();
1205 return -1;
1206 }
1207 return 1;
1208 }
1209
1210
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)
1222 {
1223 // phpcs:enable
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')";
1228
1229 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1230 $resql = $this->query($sql);
1231 if (!$resql) {
1232 return -1;
1233 }
1234
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')";
1239
1240 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1241 $resql = $this->query($sql);
1242 if (!$resql) {
1243 return -1;
1244 }
1245
1246 $sql = "FLUSH Privileges";
1247
1248 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1249 $resql = $this->query($sql);
1250 if (!$resql) {
1251 return -1;
1252 }
1253 return 1;
1254 }
1255
1261 public function getDefaultCharacterSetDatabase()
1262 {
1263 return 'UTF-8';
1264 }
1265
1271 public function getListOfCharacterSet()
1272 {
1273 $liste = array();
1274 $i = 0;
1275 $liste[$i]['charset'] = 'UTF-8';
1276 $liste[$i]['description'] = 'UTF-8';
1277 return $liste;
1278 }
1279
1285 public function getDefaultCollationDatabase()
1286 {
1287 return 'UTF-8';
1288 }
1289
1295 public function getListOfCollation()
1296 {
1297 $liste = array();
1298 $i = 0;
1299 $liste[$i]['collation'] = 'UTF-8';
1300 return $liste;
1301 }
1302
1308 public function getPathOfDump()
1309 {
1310 // FIXME: not for SQLite
1311 $fullpathofdump = '/pathtomysqldump/mysqldump';
1312
1313 $resql = $this->query("SHOW VARIABLES LIKE 'basedir'");
1314 if ($resql) {
1315 $liste = $this->fetch_array($resql);
1316 $basedir = $liste['Value'];
1317 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1318 }
1319 return $fullpathofdump;
1320 }
1321
1327 public function getPathOfRestore()
1328 {
1329 // FIXME: not for SQLite
1330 $fullpathofimport = '/pathtomysql/mysql';
1331
1332 $resql = $this->query("SHOW VARIABLES LIKE 'basedir'");
1333 if ($resql) {
1334 $liste = $this->fetch_array($resql);
1335 $basedir = $liste['Value'];
1336 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1337 }
1338 return $fullpathofimport;
1339 }
1340
1347 public function getServerParametersValues($filter = '')
1348 {
1349 $result = array();
1350 static $pragmas;
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
1355 $pragmas = array(
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',
1369 );
1370 }
1371
1372 // TODO prendre en compte le filtre
1373 foreach ($pragmas as $var) {
1374 $sql = "PRAGMA $var";
1375 $resql = $this->query($sql);
1376 if ($resql) {
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];
1380 } else {
1381 // TODO Retrieve the message
1382 $result[$var] = 'FAIL';
1383 }
1384 }
1385 return $result;
1386 }
1387
1394 public function getServerStatusValues($filter = '')
1395 {
1396 $result = array();
1397 /*
1398 $sql='SHOW STATUS';
1399 if ($filter) {
1400 $sql.=" LIKE '".$this->escape($filter)."'";
1401 }
1402 $resql=$this->query($sql);
1403 if ($resql)
1404 {
1405 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1406 }
1407 */
1408
1409 return $result;
1410 }
1411
1423 private function addCustomFunction($name, $arg_count = -1)
1424 {
1425 if ($this->db) {
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();
1432 }
1433 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1434 $this->error = "unable to create custom function '$name'";
1435 }
1436 }
1437 }
1438
1439 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1440 /* Unused/commented
1441 * calc_daynr
1442 *
1443 * param int $year Year
1444 * param int $month Month
1445 * param int $day Day
1446 * return int Formatted date
1447 */
1448 /*
1449 private static function calc_daynr($year, $month, $day)
1450 {
1451 // phpcs:enable
1452 $y = $year;
1453 if ($y == 0 && $month == 0) {
1454 return 0;
1455 }
1456 $num = (365 * $y + 31 * ($month - 1) + $day);
1457 if ($month <= 2) {
1458 $y--;
1459 } else {
1460 $num -= floor(($month * 4 + 23) / 10);
1461 }
1462 $temp = floor(($y / 100 + 1) * 3 / 4);
1463 return (int) ($num + floor($y / 4) - $temp);
1464 }
1465 */
1466
1467 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1468 /* Unused/commented
1469 * calc_weekday
1470 *
1471 * param int $daynr ???
1472 * param bool $sunday_first_day_of_week ???
1473 * return int
1474 */
1475 /*
1476 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1477 {
1478 // phpcs:enable
1479 $ret = (int) floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1480 return $ret;
1481 }
1482 */
1483
1484 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1485 /* Unused/commented
1486 * calc_days_in_year
1487 *
1488 * param int $year Year
1489 * return int Nb of days in year
1490 */
1491 /*
1492 private static function calc_days_in_year($year)
1493 {
1494 // phpcs:enable
1495 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1496 }
1497 */
1498
1499 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1500 /* Unused/commented
1501 * calc_week
1502 *
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
1509 */
1510 /*
1511 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1512 {
1513 // phpcs:enable
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;
1519
1520 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1521 $calc_year = $year;
1522
1523 if ($month == 1 && $day <= 7 - $weekday) {
1524 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1525 return 0;
1526 }
1527 $week_year = 1;
1528 $calc_year--;
1529 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1530 $weekday = ($weekday + 53 * 7 - $days) % 7;
1531 }
1532
1533 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1534 $days = $daynr - ($first_daynr + (7 - $weekday));
1535 } else {
1536 $days = $daynr - ($first_daynr - $weekday);
1537 }
1538
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)) {
1542 $calc_year++;
1543 return 1;
1544 }
1545 }
1546 return (int) floor($days / 7 + 1);
1547 }
1548 */
1549}
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.
$type
Database type.
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.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
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]]]',...
Definition repair.php:130