dolibarr 21.0.0-alpha
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 MDW <mdeweerd@users.noreply.github.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 */
23
29require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
30
34class DoliDBSqlite3 extends DoliDB
35{
37 public $type = 'sqlite3';
39 const LABEL = 'Sqlite3';
41 const VERSIONMIN = '3.0.0';
42
46 private $_results;
47
51 private $queryString;
52
53 const WEEK_MONDAY_FIRST = 1;
54 const WEEK_YEAR = 2;
55 const WEEK_FIRST_WEEKDAY = 4;
56
57
69 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
70 {
71 global $conf;
72
73 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
74 if (!empty($conf->db->character_set)) {
75 $this->forcecharset = $conf->db->character_set;
76 }
77 if (!empty($conf->db->dolibarr_main_db_collation)) {
78 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
79 }
80
81 $this->database_user = $user;
82 $this->database_host = $host;
83 $this->database_port = $port;
84
85 $this->transaction_opened = 0;
86
87 //print "Name DB: $host,$user,$pass,$name<br>";
88
89 /*if (! function_exists("sqlite_query"))
90 {
91 $this->connected = false;
92 $this->ok = false;
93 $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
94 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);
95 return;
96 }*/
97
98 /*if (! $host)
99 {
100 $this->connected = false;
101 $this->ok = false;
102 $this->error=$langs->trans("ErrorWrongHostParameter");
103 dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
104 return;
105 }*/
106
107 // Essai connection serveur
108 // We do not try to connect to database, only to server. Connect to database is done later in constructor
109 $this->db = $this->connect($host, $user, $pass, $name, $port);
110
111 if ($this->db) {
112 $this->connected = true;
113 $this->ok = true;
114 $this->database_selected = true;
115 $this->database_name = $name;
116
117 $this->addCustomFunction('IF');
118 $this->addCustomFunction('MONTH');
119 $this->addCustomFunction('CURTIME');
120 $this->addCustomFunction('CURDATE');
121 $this->addCustomFunction('WEEK', 1);
122 $this->addCustomFunction('WEEK', 2);
123 $this->addCustomFunction('WEEKDAY');
124 $this->addCustomFunction('date_format');
125 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
126 } else {
127 // host, login ou password incorrect
128 $this->connected = false;
129 $this->ok = false;
130 $this->database_selected = false;
131 $this->database_name = '';
132 //$this->error=sqlite_connect_error();
133 dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error, LOG_ERR);
134 }
135 }
136
137
145 public function convertSQLFromMysql($line, $type = 'ddl')
146 {
147 // Removed empty line if this is a comment line for SVN tagging
148 if (preg_match('/^--\s\$Id/i', $line)) {
149 return '';
150 }
151 // Return line if this is a comment
152 if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
153 return $line;
154 }
155 if ($line != "") {
156 if ($type == 'auto') {
157 if (preg_match('/ALTER TABLE/i', $line)) {
158 $type = 'dml';
159 } elseif (preg_match('/CREATE TABLE/i', $line)) {
160 $type = 'dml';
161 } elseif (preg_match('/DROP TABLE/i', $line)) {
162 $type = 'dml';
163 }
164 }
165
166 if ($type == 'dml') {
167 $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
168
169 // we are inside create table statement so let's process datatypes
170 if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
171 $line = preg_replace('/\‍)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
172 $line = preg_replace('/\‍)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
173 $line = preg_replace('/,$/', '', $line);
174 }
175
176 // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
177 if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
178 $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
179 //$line = "-- ".$line." replaced by --\n".$newline;
180 $line = $newline;
181 }
182
183 // tinyint type conversion
184 $line = str_replace('tinyint', 'smallint', $line);
185
186 // nuke unsigned
187 $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
188
189 // blob -> text
190 $line = preg_replace('/\w*blob/i', 'text', $line);
191
192 // tinytext/mediumtext -> text
193 $line = preg_replace('/tinytext/i', 'text', $line);
194 $line = preg_replace('/mediumtext/i', 'text', $line);
195
196 // change not null datetime field to null valid ones
197 // (to support remapping of "zero time" to null
198 $line = preg_replace('/datetime not null/i', 'datetime', $line);
199 $line = preg_replace('/datetime/i', 'timestamp', $line);
200
201 // double -> numeric
202 $line = preg_replace('/^double/i', 'numeric', $line);
203 $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
204 // float -> numeric
205 $line = preg_replace('/^float/i', 'numeric', $line);
206 $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
207
208 // unique index(field1,field2)
209 if (preg_match('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', $line)) {
210 $line = preg_replace('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', 'UNIQUE\‍(\\1\‍)', $line);
211 }
212
213 // We remove end of requests "AFTER fieldxxx"
214 $line = preg_replace('/AFTER [a-z0-9_]+/i', '', $line);
215
216 // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
217 $line = preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i', 'DROP INDEX', $line);
218
219 // Translate order to rename fields
220 if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
221 $line = "-- ".$line." replaced by --\n";
222 $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
223 }
224
225 // Translate order to modify field format
226 if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
227 $line = "-- ".$line." replaced by --\n";
228 $newreg3 = $reg[3];
229 $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
230 $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
231 $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
232 $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
233 $newreg3 = preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i', '', $newreg3);
234 $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
235 // TODO Add alter to set default value or null/not null if there is this in $reg[3]
236 }
237
238 // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
239 // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
240 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\‍((.*)$/i', $line, $reg)) {
241 $line = "-- ".$line." replaced by --\n";
242 $line .= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3];
243 }
244
245 // Translate order to drop foreign keys
246 // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
247 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
248 $line = "-- ".$line." replaced by --\n";
249 $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
250 }
251
252 // alter table add [unique] [index] (field1, field2 ...)
253 // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
254 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
255 $fieldlist = $reg[4];
256 $idxname = $reg[3];
257 $tablename = $reg[1];
258 $line = "-- ".$line." replaced by --\n";
259 $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
260 }
261 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)) {
262 // Pour l'instant les contraintes ne sont pas créées
263 dol_syslog(get_class().'::query line emptied');
264 $line = 'SELECT 0;';
265 }
266
267 //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
268 //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
269 //}
270 }
271
272 // Delete using criteria on other table must not declare twice the deleted table
273 // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
274 if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
275 if ($reg[1] == $reg[2]) { // If same table, we remove second one
276 $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
277 }
278 }
279
280 // Remove () in the tables in FROM if one table
281 $line = preg_replace('/FROM\s*\‍((([a-z_]+)\s+as\s+([a-z_]+)\s*)\‍)/i', 'FROM \\1', $line);
282 //print $line."\n";
283
284 // Remove () in the tables in FROM if two table
285 $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);
286 //print $line."\n";
287
288 // Remove () in the tables in FROM if two table
289 $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);
290 //print $line."\n";
291
292 //print "type=".$type." newline=".$line."<br>\n";
293 }
294
295 return $line;
296 }
297
298 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
305 public function select_db($database)
306 {
307 // phpcs:enable
308 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
309 // sqlite_select_db() does not exist
310 //return sqlite_select_db($this->db,$database);
311 return true;
312 }
313
314
326 public function connect($host, $login, $passwd, $name, $port = 0)
327 {
328 global $main_data_dir;
329
330 dol_syslog(get_class($this)."::connect name=".$name, LOG_DEBUG);
331
332 $dir = $main_data_dir;
333 if (empty($dir)) {
334 $dir = DOL_DATA_ROOT;
335 }
336 // With sqlite, port must be in connect parameters
337 //if (! $newport) $newport=3306;
338 $database_name = $dir.'/database_'.$name.'.sdb';
339 try {
340 /*** connect to SQLite database ***/
341 //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
342 $this->db = new SQLite3($database_name);
343 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
344 } catch (Exception $e) {
345 $this->error = self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
346 return false;
347 }
348
349 //print "Resultat fonction connect: ".$this->db;
350 return $this->db;
351 }
352
353
359 public function getVersion()
360 {
361 $tmp = $this->db->version();
362 return $tmp['versionString'];
363 }
364
370 public function getDriverInfo()
371 {
372 return 'sqlite3 php driver';
373 }
374
375
382 public function close()
383 {
384 if ($this->db) {
385 if ($this->transaction_opened > 0) {
386 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
387 }
388 $this->connected = false;
389 $this->db->close();
390 unset($this->db); // Clean this->db
391 return true;
392 }
393 return false;
394 }
395
406 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
407 {
408 global $conf, $dolibarr_main_db_readonly;
409
410 $ret = false;
411
412 $query = trim($query);
413
414 $this->error = '';
415
416 // Convert MySQL syntax to SQLite syntax
417 $reg = array();
418 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)) {
419 // Ajout d'une clef étrangère à la table
420 // procédure de replacement de la table pour ajouter la contrainte
421 // Example : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
422 // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
423 $foreignFields = $reg[5];
424 $foreignTable = $reg[4];
425 $localfields = $reg[3];
426 $constraintname = trim($reg[2]);
427 $tablename = trim($reg[1]);
428
429 $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='".$this->escape($tablename)."'");
430
431 // 1- Renommer la table avec un nom temporaire
432 $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
433
434 // 2- Recréer la table avec la contrainte ajoutée
435
436 // on bricole la requete pour ajouter la contrainte
437 $descTable = substr($descTable, 0, strlen($descTable) - 1);
438 $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
439
440 // fermeture de l'instruction
441 $descTable .= ')';
442
443 // Création proprement dite de la table
444 $this->query($descTable);
445
446 // 3- Transférer les données
447 $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
448
449 // 4- Supprimer la table temporaire
450 $this->query("DROP TABLE tmp_".$tablename);
451
452 // dummy statement
453 $query = "SELECT 0";
454 } else {
455 $query = $this->convertSQLFromMysql($query, $type);
456 }
457 //print "After convertSQLFromMysql:\n".$query."<br>\n";
458
459 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
460 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
461 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
462 }
463 if (empty($query)) {
464 return false; // Return false = error if empty request
465 }
466
467 if (!empty($dolibarr_main_db_readonly)) {
468 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
469 $this->lasterror = 'Application in read-only mode';
470 $this->lasterrno = 'APPREADONLY';
471 $this->lastquery = $query;
472 return false;
473 }
474 }
475
476 // Ordre SQL ne necessitant pas de connection a une base (example: CREATE DATABASE)
477 try {
478 //$ret = $this->db->exec($query);
479 $ret = $this->db->query($query); // $ret is a Sqlite3Result
480 if ($ret) {
481 $this->queryString = $query;
482 }
483 } catch (Exception $e) {
484 $this->error = $this->db->lastErrorMsg();
485 }
486
487 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
488 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
489 if (!is_object($ret) || $this->error) {
490 $this->lastqueryerror = $query;
491 $this->lasterror = $this->error();
492 $this->lasterrno = $this->errno();
493
494 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
495
496 $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
497
498 if (preg_match('/[0-9]/', $this->lasterrno)) {
499 $errormsg .= ' ('.$this->lasterrno.')';
500 }
501
502 if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) {
503 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
504 }
505 dol_syslog(get_class($this)."::query SQL Error message: ".$errormsg, LOG_ERR);
506 }
507 $this->lastquery = $query;
508 $this->_results = $ret;
509 }
510
511 return $ret;
512 }
513
514 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
521 public function fetch_object($resultset)
522 {
523 // phpcs:enable
524 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connection
525 if (!is_object($resultset)) {
526 $resultset = $this->_results;
527 }
528 //return $resultset->fetch(PDO::FETCH_OBJ);
529 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
530 if ($ret) {
531 return (object) $ret;
532 }
533 return false;
534 }
535
536
537 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
544 public function fetch_array($resultset)
545 {
546 // phpcs:enable
547 // If resultset not provided, we take the last used by connection
548 if (!is_object($resultset)) {
549 $resultset = $this->_results;
550 }
551 //return $resultset->fetch(PDO::FETCH_ASSOC);
552 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
553 return $ret;
554 }
555
556 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
563 public function fetch_row($resultset)
564 {
565 // phpcs:enable
566 // If resultset not provided, we take the last used by connection
567 if (!is_bool($resultset)) {
568 if (!is_object($resultset)) {
569 $resultset = $this->_results;
570 }
571 return $resultset->fetchArray(SQLITE3_NUM);
572 } else {
573 // si le curseur est un boolean on retourne la valeur 0
574 return 0;
575 }
576 }
577
578 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
586 public function num_rows($resultset)
587 {
588 // phpcs:enable
589
590 // If resultset not provided, we take the last used by connection
591 if (!is_object($resultset)) {
592 $resultset = $this->_results;
593 }
594 // Ignore Phan - queryString is added as dynamic property @phan-suppress-next-line PhanUndeclaredProperty
595 if (preg_match("/^SELECT/i", $resultset->queryString)) {
596 // Ignore Phan - queryString is added as dynamic property @phan-suppress-next-line PhanUndeclaredProperty
597 return $this->db->querySingle("SELECT count(*) FROM (".$resultset->queryString.") q");
598 }
599 return 0;
600 }
601
602 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
610 public function affected_rows($resultset)
611 {
612 // phpcs:enable
613
614 // If resultset not provided, we take the last used by connection
615 if (!is_object($resultset)) {
616 $resultset = $this->_results;
617 }
618 if (preg_match("/^SELECT/i", $this->queryString)) {
619 return $this->num_rows($resultset);
620 }
621 // mysql necessite un link de base pour cette fonction contrairement
622 // a pqsql qui prend un 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 $like = '';
885 if ($table) {
886 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
887
888 $like = "LIKE '".$this->escape($tmptable)."'";
889 }
890 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
891
892 $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
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 $like = '';
917 if ($table) {
918 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
919
920 $like = "LIKE '".$this->escape($tmptable)."'";
921 }
922 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
923
924 $sql = "SHOW FULL TABLES FROM ".$tmpdatabase." ".$like.";";
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 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
950
951 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
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 $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1022 } else {
1023 $pk = "";
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 .= ",".$pk;
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 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1072
1073 $sql = "DROP TABLE ".$tmptable;
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 ".$table." ".$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 ".$table." ADD ".$field_name." ";
1116 $sql .= $field_desc['type'];
1117 if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) {
1118 if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1119 $sql .= "(".$field_desc['value'].")";
1120 }
1121 }
1122 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1123 $sql .= " ".$this->sanitize($field_desc['attribute']);
1124 }
1125 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
1126 $sql .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1127 }
1128 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
1129 if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
1130 $sql .= " DEFAULT ".((float) $field_desc['default']);
1131 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
1132 $sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
1133 } else {
1134 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1135 }
1136 }
1137 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
1138 $sql .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1139 }
1140 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1141
1142 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1143 if (!$this->query($sql)) {
1144 return -1;
1145 }
1146 return 1;
1147 }
1148
1149 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1158 public function DDLUpdateField($table, $field_name, $field_desc)
1159 {
1160 // phpcs:enable
1161 $sql = "ALTER TABLE ".$this->sanitize($table);
1162 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ".$this->sanitize($field_desc['type']);
1163 if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1164 $sql .= "(".$this->sanitize($field_desc['value']).")";
1165 }
1166
1167 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1168 if (!$this->query($sql)) {
1169 return -1;
1170 }
1171 return 1;
1172 }
1173
1174 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1182 public function DDLDropField($table, $field_name)
1183 {
1184 // phpcs:enable
1185 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1186
1187 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1188 if (!$this->query($sql)) {
1189 $this->error = $this->lasterror();
1190 return -1;
1191 }
1192 return 1;
1193 }
1194
1195
1196 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1206 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1207 {
1208 // phpcs:enable
1209 $sql = "INSERT INTO user ";
1210 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1211 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1212 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1213
1214 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1215 $resql = $this->query($sql);
1216 if (!$resql) {
1217 return -1;
1218 }
1219
1220 $sql = "INSERT INTO db ";
1221 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1222 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1223 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1224
1225 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1226 $resql = $this->query($sql);
1227 if (!$resql) {
1228 return -1;
1229 }
1230
1231 $sql = "FLUSH Privileges";
1232
1233 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1234 $resql = $this->query($sql);
1235 if (!$resql) {
1236 return -1;
1237 }
1238 return 1;
1239 }
1240
1246 public function getDefaultCharacterSetDatabase()
1247 {
1248 return 'UTF-8';
1249 }
1250
1256 public function getListOfCharacterSet()
1257 {
1258 $liste = array();
1259 $i = 0;
1260 $liste[$i]['charset'] = 'UTF-8';
1261 $liste[$i]['description'] = 'UTF-8';
1262 return $liste;
1263 }
1264
1270 public function getDefaultCollationDatabase()
1271 {
1272 return 'UTF-8';
1273 }
1274
1280 public function getListOfCollation()
1281 {
1282 $liste = array();
1283 $i = 0;
1284 $liste[$i]['charset'] = 'UTF-8';
1285 $liste[$i]['description'] = 'UTF-8';
1286 return $liste;
1287 }
1288
1294 public function getPathOfDump()
1295 {
1296 // FIXME: not for SQLite
1297 $fullpathofdump = '/pathtomysqldump/mysqldump';
1298
1299 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1300 if ($resql) {
1301 $liste = $this->fetch_array($resql);
1302 $basedir = $liste['Value'];
1303 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1304 }
1305 return $fullpathofdump;
1306 }
1307
1313 public function getPathOfRestore()
1314 {
1315 // FIXME: not for SQLite
1316 $fullpathofimport = '/pathtomysql/mysql';
1317
1318 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1319 if ($resql) {
1320 $liste = $this->fetch_array($resql);
1321 $basedir = $liste['Value'];
1322 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1323 }
1324 return $fullpathofimport;
1325 }
1326
1333 public function getServerParametersValues($filter = '')
1334 {
1335 $result = array();
1336 static $pragmas;
1337 if (!isset($pragmas)) {
1338 // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1339 // indépendante de la base de données.
1340 // cf. http://www.sqlite.org/pragma.html
1341 $pragmas = array(
1342 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1343 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1344 'compile_options', 'data_version', /*'database_list',*/
1345 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1346 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1347 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1348 'max_page_count', 'page_count', 'page_size', 'parser_trace',
1349 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1350 'reverse_unordered_selects', 'schema_version', 'user_version',
1351 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1352 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1353 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1354 'wal_autocheckpoint',
1355 );
1356 }
1357
1358 // TODO prendre en compte le filtre
1359 foreach ($pragmas as $var) {
1360 $sql = "PRAGMA $var";
1361 $resql = $this->query($sql);
1362 if ($resql) {
1363 $obj = $this->fetch_row($resql);
1364 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1365 $result[$var] = $obj[0];
1366 } else {
1367 // TODO Récupérer le message
1368 $result[$var] = 'FAIL';
1369 }
1370 }
1371 return $result;
1372 }
1373
1380 public function getServerStatusValues($filter = '')
1381 {
1382 $result = array();
1383 /*
1384 $sql='SHOW STATUS';
1385 if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1386 $resql=$this->query($sql);
1387 if ($resql)
1388 {
1389 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1390 }
1391 */
1392
1393 return $result;
1394 }
1395
1407 private function addCustomFunction($name, $arg_count = -1)
1408 {
1409 if ($this->db) {
1410 $newname = preg_replace('/_/', '', $name);
1411 $localname = __CLASS__.'::db'.$newname;
1412 $reflectClass = new ReflectionClass(__CLASS__);
1413 $reflectFunction = $reflectClass->getMethod('db'.$newname);
1414 if ($arg_count < 0) {
1415 $arg_count = $reflectFunction->getNumberOfParameters();
1416 }
1417 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1418 $this->error = "unable to create custom function '$name'";
1419 }
1420 }
1421 }
1422
1423 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1424 /* Unused/commented
1425 * calc_daynr
1426 *
1427 * param int $year Year
1428 * param int $month Month
1429 * param int $day Day
1430 * return int Formatted date
1431 */
1432 /*
1433 private static function calc_daynr($year, $month, $day)
1434 {
1435 // phpcs:enable
1436 $y = $year;
1437 if ($y == 0 && $month == 0) {
1438 return 0;
1439 }
1440 $num = (365 * $y + 31 * ($month - 1) + $day);
1441 if ($month <= 2) {
1442 $y--;
1443 } else {
1444 $num -= floor(($month * 4 + 23) / 10);
1445 }
1446 $temp = floor(($y / 100 + 1) * 3 / 4);
1447 return (int) ($num + floor($y / 4) - $temp);
1448 }
1449 */
1450
1451 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1452 /* Unused/commented
1453 * calc_weekday
1454 *
1455 * param int $daynr ???
1456 * param bool $sunday_first_day_of_week ???
1457 * return int
1458 */
1459 /*
1460 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1461 {
1462 // phpcs:enable
1463 $ret = (int) floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1464 return $ret;
1465 }
1466 */
1467
1468 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1469 /* Unused/commented
1470 * calc_days_in_year
1471 *
1472 * param int $year Year
1473 * return int Nb of days in year
1474 */
1475 /*
1476 private static function calc_days_in_year($year)
1477 {
1478 // phpcs:enable
1479 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1480 }
1481 */
1482
1483 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1484 /* Unused/commented
1485 * calc_week
1486 *
1487 * param int $year Year
1488 * param int $month Month
1489 * param int $day Day
1490 * param int $week_behaviour Week behaviour, bit masks: WEEK_MONDAY_FIRST, WEEK_YEAR, WEEK_FIRST_WEEKDAY
1491 * param int $calc_year ??? Year where the week started
1492 * return int ??? Week number in year
1493 */
1494 /*
1495 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1496 {
1497 // phpcs:enable
1498 $daynr = self::calc_daynr($year, $month, $day);
1499 $first_daynr = self::calc_daynr($year, 1, 1);
1500 $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1501 $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1502 $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1503
1504 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1505 $calc_year = $year;
1506
1507 if ($month == 1 && $day <= 7 - $weekday) {
1508 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1509 return 0;
1510 }
1511 $week_year = 1;
1512 $calc_year--;
1513 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1514 $weekday = ($weekday + 53 * 7 - $days) % 7;
1515 }
1516
1517 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1518 $days = $daynr - ($first_daynr + (7 - $weekday));
1519 } else {
1520 $days = $daynr - ($first_daynr - $weekday);
1521 }
1522
1523 if ($week_year && $days >= 52 * 7) {
1524 $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1525 if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1526 $calc_year++;
1527 return 1;
1528 }
1529 }
1530 return (int) floor($days / 7 + 1);
1531 }
1532 */
1533}
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.
getPathOfRestore()
Return full path of restore program.
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.
getServerParametersValues($filter='')
Return value of server parameters.
free($resultset=null)
Free last resultset used.
__construct($type, $host, $user, $pass, $name='', $port=0)
Constructor.
const VERSIONMIN
Version min database.
getServerStatusValues($filter='')
Return value of server status.
$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.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:137