dolibarr 19.0.3
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 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 */
22
28require_once DOL_DOCUMENT_ROOT.'/core/db/DoliDB.class.php';
29
33class DoliDBSqlite3 extends DoliDB
34{
36 public $type = 'sqlite3';
38 const LABEL = 'Sqlite3';
40 const VERSIONMIN = '3.0.0';
41
45 private $_results;
46
47 const WEEK_MONDAY_FIRST = 1;
48 const WEEK_YEAR = 2;
49 const WEEK_FIRST_WEEKDAY = 4;
50
51
63 public function __construct($type, $host, $user, $pass, $name = '', $port = 0)
64 {
65 global $conf;
66
67 // Note that having "static" property for "$forcecharset" and "$forcecollate" will make error here in strict mode, so they are not static
68 if (!empty($conf->db->character_set)) {
69 $this->forcecharset = $conf->db->character_set;
70 }
71 if (!empty($conf->db->dolibarr_main_db_collation)) {
72 $this->forcecollate = $conf->db->dolibarr_main_db_collation;
73 }
74
75 $this->database_user = $user;
76 $this->database_host = $host;
77 $this->database_port = $port;
78
79 $this->transaction_opened = 0;
80
81 //print "Name DB: $host,$user,$pass,$name<br>";
82
83 /*if (! function_exists("sqlite_query"))
84 {
85 $this->connected = false;
86 $this->ok = false;
87 $this->error="Sqlite PHP functions for using Sqlite driver are not available in this version of PHP. Try to use another driver.";
88 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);
89 return;
90 }*/
91
92 /*if (! $host)
93 {
94 $this->connected = false;
95 $this->ok = false;
96 $this->error=$langs->trans("ErrorWrongHostParameter");
97 dol_syslog(get_class($this)."::DoliDBSqlite3 : Erreur Connect, wrong host parameters",LOG_ERR);
98 return;
99 }*/
100
101 // Essai connexion serveur
102 // We do not try to connect to database, only to server. Connect to database is done later in constrcutor
103 $this->db = $this->connect($host, $user, $pass, $name, $port);
104
105 if ($this->db) {
106 $this->connected = true;
107 $this->ok = true;
108 $this->database_selected = true;
109 $this->database_name = $name;
110
111 $this->addCustomFunction('IF');
112 $this->addCustomFunction('MONTH');
113 $this->addCustomFunction('CURTIME');
114 $this->addCustomFunction('CURDATE');
115 $this->addCustomFunction('WEEK', 1);
116 $this->addCustomFunction('WEEK', 2);
117 $this->addCustomFunction('WEEKDAY');
118 $this->addCustomFunction('date_format');
119 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
120 } else {
121 // host, login ou password incorrect
122 $this->connected = false;
123 $this->ok = false;
124 $this->database_selected = false;
125 $this->database_name = '';
126 //$this->error=sqlite_connect_error();
127 dol_syslog(get_class($this)."::DoliDBSqlite3 : Error Connect ".$this->error, LOG_ERR);
128 }
129 }
130
131
139 public function convertSQLFromMysql($line, $type = 'ddl')
140 {
141 // Removed empty line if this is a comment line for SVN tagging
142 if (preg_match('/^--\s\$Id/i', $line)) {
143 return '';
144 }
145 // Return line if this is a comment
146 if (preg_match('/^#/i', $line) || preg_match('/^$/i', $line) || preg_match('/^--/i', $line)) {
147 return $line;
148 }
149 if ($line != "") {
150 if ($type == 'auto') {
151 if (preg_match('/ALTER TABLE/i', $line)) {
152 $type = 'dml';
153 } elseif (preg_match('/CREATE TABLE/i', $line)) {
154 $type = 'dml';
155 } elseif (preg_match('/DROP TABLE/i', $line)) {
156 $type = 'dml';
157 }
158 }
159
160 if ($type == 'dml') {
161 $line = preg_replace('/\s/', ' ', $line); // Replace tabulation with space
162
163 // we are inside create table statement so lets process datatypes
164 if (preg_match('/(ISAM|innodb)/i', $line)) { // end of create table sequence
165 $line = preg_replace('/\‍)[\s\t]*type[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
166 $line = preg_replace('/\‍)[\s\t]*engine[\s\t]*=[\s\t]*(MyISAM|innodb);/i', ');', $line);
167 $line = preg_replace('/,$/', '', $line);
168 }
169
170 // Process case: "CREATE TABLE llx_mytable(rowid integer NOT NULL AUTO_INCREMENT PRIMARY KEY,code..."
171 if (preg_match('/[\s\t\‍(]*(\w*)[\s\t]+int.*auto_increment/i', $line, $reg)) {
172 $newline = preg_replace('/([\s\t\‍(]*)([a-zA-Z_0-9]*)[\s\t]+int.*auto_increment[^,]*/i', '\\1 \\2 integer PRIMARY KEY AUTOINCREMENT', $line);
173 //$line = "-- ".$line." replaced by --\n".$newline;
174 $line = $newline;
175 }
176
177 // tinyint type conversion
178 $line = str_replace('tinyint', 'smallint', $line);
179
180 // nuke unsigned
181 $line = preg_replace('/(int\w+|smallint)\s+unsigned/i', '\\1', $line);
182
183 // blob -> text
184 $line = preg_replace('/\w*blob/i', 'text', $line);
185
186 // tinytext/mediumtext -> text
187 $line = preg_replace('/tinytext/i', 'text', $line);
188 $line = preg_replace('/mediumtext/i', 'text', $line);
189
190 // change not null datetime field to null valid ones
191 // (to support remapping of "zero time" to null
192 $line = preg_replace('/datetime not null/i', 'datetime', $line);
193 $line = preg_replace('/datetime/i', 'timestamp', $line);
194
195 // double -> numeric
196 $line = preg_replace('/^double/i', 'numeric', $line);
197 $line = preg_replace('/(\s*)double/i', '\\1numeric', $line);
198 // float -> numeric
199 $line = preg_replace('/^float/i', 'numeric', $line);
200 $line = preg_replace('/(\s*)float/i', '\\1numeric', $line);
201
202 // unique index(field1,field2)
203 if (preg_match('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', $line)) {
204 $line = preg_replace('/unique index\s*\‍((\w+\s*,\s*\w+)\‍)/i', 'UNIQUE\‍(\\1\‍)', $line);
205 }
206
207 // We remove end of requests "AFTER fieldxxx"
208 $line = preg_replace('/AFTER [a-z0-9_]+/i', '', $line);
209
210 // We remove start of requests "ALTER TABLE tablexxx" if this is a DROP INDEX
211 $line = preg_replace('/ALTER TABLE [a-z0-9_]+ DROP INDEX/i', 'DROP INDEX', $line);
212
213 // Translate order to rename fields
214 if (preg_match('/ALTER TABLE ([a-z0-9_]+) CHANGE(?: COLUMN)? ([a-z0-9_]+) ([a-z0-9_]+)(.*)$/i', $line, $reg)) {
215 $line = "-- ".$line." replaced by --\n";
216 $line .= "ALTER TABLE ".$reg[1]." RENAME COLUMN ".$reg[2]." TO ".$reg[3];
217 }
218
219 // Translate order to modify field format
220 if (preg_match('/ALTER TABLE ([a-z0-9_]+) MODIFY(?: COLUMN)? ([a-z0-9_]+) (.*)$/i', $line, $reg)) {
221 $line = "-- ".$line." replaced by --\n";
222 $newreg3 = $reg[3];
223 $newreg3 = preg_replace('/ DEFAULT NULL/i', '', $newreg3);
224 $newreg3 = preg_replace('/ NOT NULL/i', '', $newreg3);
225 $newreg3 = preg_replace('/ NULL/i', '', $newreg3);
226 $newreg3 = preg_replace('/ DEFAULT 0/i', '', $newreg3);
227 $newreg3 = preg_replace('/ DEFAULT \'[0-9a-zA-Z_@]*\'/i', '', $newreg3);
228 $line .= "ALTER TABLE ".$reg[1]." ALTER COLUMN ".$reg[2]." TYPE ".$newreg3;
229 // TODO Add alter to set default value or null/not null if there is this in $reg[3]
230 }
231
232 // alter table add primary key (field1, field2 ...) -> We create a unique index instead as dynamic creation of primary key is not supported
233 // ALTER TABLE llx_dolibarr_modules ADD PRIMARY KEY pk_dolibarr_modules (numero, entity);
234 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+PRIMARY\s+KEY\s*(.*)\s*\‍((.*)$/i', $line, $reg)) {
235 $line = "-- ".$line." replaced by --\n";
236 $line .= "CREATE UNIQUE INDEX ".$reg[2]." ON ".$reg[1]."(".$reg[3];
237 }
238
239 // Translate order to drop foreign keys
240 // ALTER TABLE llx_dolibarr_modules DROP FOREIGN KEY fk_xxx;
241 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*DROP\s+FOREIGN\s+KEY\s*(.*)$/i', $line, $reg)) {
242 $line = "-- ".$line." replaced by --\n";
243 $line .= "ALTER TABLE ".$reg[1]." DROP CONSTRAINT ".$reg[2];
244 }
245
246 // alter table add [unique] [index] (field1, field2 ...)
247 // ALTER TABLE llx_accountingaccount ADD INDEX idx_accountingaccount_fk_pcg_version (fk_pcg_version)
248 if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+(UNIQUE INDEX|INDEX|UNIQUE)\s+(.*)\s*\‍(([\w,\s]+)\‍)/i', $line, $reg)) {
249 $fieldlist = $reg[4];
250 $idxname = $reg[3];
251 $tablename = $reg[1];
252 $line = "-- ".$line." replaced by --\n";
253 $line .= "CREATE ".(preg_match('/UNIQUE/', $reg[2]) ? 'UNIQUE ' : '')."INDEX ".$idxname." ON ".$tablename." (".$fieldlist.")";
254 }
255 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)) {
256 // Pour l'instant les contraintes ne sont pas créées
257 dol_syslog(get_class().'::query line emptied');
258 $line = 'SELECT 0;';
259 }
260
261 //if (preg_match('/rowid\s+.*\s+PRIMARY\s+KEY,/i', $line)) {
262 //preg_replace('/(rowid\s+.*\s+PRIMARY\s+KEY\s*,)/i', '/* \\1 */', $line);
263 //}
264 }
265
266 // Delete using criteria on other table must not declare twice the deleted table
267 // DELETE FROM tabletodelete USING tabletodelete, othertable -> DELETE FROM tabletodelete USING othertable
268 if (preg_match('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', $line, $reg)) {
269 if ($reg[1] == $reg[2]) { // If same table, we remove second one
270 $line = preg_replace('/DELETE FROM ([a-z_]+) USING ([a-z_]+), ([a-z_]+)/i', 'DELETE FROM \\1 USING \\3', $line);
271 }
272 }
273
274 // Remove () in the tables in FROM if one table
275 $line = preg_replace('/FROM\s*\‍((([a-z_]+)\s+as\s+([a-z_]+)\s*)\‍)/i', 'FROM \\1', $line);
276 //print $line."\n";
277
278 // Remove () in the tables in FROM if two table
279 $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);
280 //print $line."\n";
281
282 // Remove () in the tables in FROM if two table
283 $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);
284 //print $line."\n";
285
286 //print "type=".$type." newline=".$line."<br>\n";
287 }
288
289 return $line;
290 }
291
292 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
299 public function select_db($database)
300 {
301 // phpcs:enable
302 dol_syslog(get_class($this)."::select_db database=".$database, LOG_DEBUG);
303 // sqlite_select_db() does not exist
304 //return sqlite_select_db($this->db,$database);
305 return true;
306 }
307
308
320 public function connect($host, $login, $passwd, $name, $port = 0)
321 {
322 global $main_data_dir;
323
324 dol_syslog(get_class($this)."::connect name=".$name, LOG_DEBUG);
325
326 $dir = $main_data_dir;
327 if (empty($dir)) {
328 $dir = DOL_DATA_ROOT;
329 }
330 // With sqlite, port must be in connect parameters
331 //if (! $newport) $newport=3306;
332 $database_name = $dir.'/database_'.$name.'.sdb';
333 try {
334 /*** connect to SQLite database ***/
335 //$this->db = new PDO("sqlite:".$dir.'/database_'.$name.'.sdb');
336 $this->db = new SQLite3($database_name);
337 //$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
338 } catch (Exception $e) {
339 $this->error = self::LABEL.' '.$e->getMessage().' current dir='.$database_name;
340 return '';
341 }
342
343 //print "Resultat fonction connect: ".$this->db;
344 return $this->db;
345 }
346
347
353 public function getVersion()
354 {
355 $tmp = $this->db->version();
356 return $tmp['versionString'];
357 }
358
364 public function getDriverInfo()
365 {
366 return 'sqlite3 php driver';
367 }
368
369
376 public function close()
377 {
378 if ($this->db) {
379 if ($this->transaction_opened > 0) {
380 dol_syslog(get_class($this)."::close Closing a connection with an opened transaction depth=".$this->transaction_opened, LOG_ERR);
381 }
382 $this->connected = false;
383 $this->db->close();
384 unset($this->db); // Clean this->db
385 return true;
386 }
387 return false;
388 }
389
400 public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0)
401 {
402 global $conf, $dolibarr_main_db_readonly;
403
404 $ret = null;
405
406 $query = trim($query);
407
408 $this->error = '';
409
410 // Convert MySQL syntax to SQLite syntax
411 $reg = array();
412 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)) {
413 // Ajout d'une clef étrangère à la table
414 // procédure de remplacement de la table pour ajouter la contrainte
415 // Exemple : ALTER TABLE llx_adherent ADD CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid)
416 // -> CREATE TABLE ( ... ,CONSTRAINT adherent_fk_soc FOREIGN KEY (fk_soc) REFERENCES llx_societe (rowid))
417 $foreignFields = $reg[5];
418 $foreignTable = $reg[4];
419 $localfields = $reg[3];
420 $constraintname = trim($reg[2]);
421 $tablename = trim($reg[1]);
422
423 $descTable = $this->db->querySingle("SELECT sql FROM sqlite_master WHERE name='".$this->escape($tablename)."'");
424
425 // 1- Renommer la table avec un nom temporaire
426 $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
427
428 // 2- Recréer la table avec la contrainte ajoutée
429
430 // on bricole la requete pour ajouter la contrainte
431 $descTable = substr($descTable, 0, strlen($descTable) - 1);
432 $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
433
434 // fermeture de l'instruction
435 $descTable .= ')';
436
437 // Création proprement dite de la table
438 $this->query($descTable);
439
440 // 3- Transférer les données
441 $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
442
443 // 4- Supprimer la table temporaire
444 $this->query("DROP TABLE tmp_".$tablename);
445
446 // dummy statement
447 $query = "SELECT 0";
448 } else {
449 $query = $this->convertSQLFromMysql($query, $type);
450 }
451 //print "After convertSQLFromMysql:\n".$query."<br>\n";
452
453 if (!in_array($query, array('BEGIN', 'COMMIT', 'ROLLBACK'))) {
454 $SYSLOG_SQL_LIMIT = 10000; // limit log to 10kb per line to limit DOS attacks
455 dol_syslog('sql='.substr($query, 0, $SYSLOG_SQL_LIMIT), LOG_DEBUG);
456 }
457 if (empty($query)) {
458 return false; // Return false = error if empty request
459 }
460
461 if (!empty($dolibarr_main_db_readonly)) {
462 if (preg_match('/^(INSERT|UPDATE|REPLACE|DELETE|CREATE|ALTER|TRUNCATE|DROP)/i', $query)) {
463 $this->lasterror = 'Application in read-only mode';
464 $this->lasterrno = 'APPREADONLY';
465 $this->lastquery = $query;
466 return false;
467 }
468 }
469
470 // Ordre SQL ne necessitant pas de connexion a une base (exemple: CREATE DATABASE)
471 try {
472 //$ret = $this->db->exec($query);
473 $ret = $this->db->query($query); // $ret is a Sqlite3Result
474 if ($ret) {
475 $ret->queryString = $query;
476 }
477 } catch (Exception $e) {
478 $this->error = $this->db->lastErrorMsg();
479 }
480
481 if (!preg_match("/^COMMIT/i", $query) && !preg_match("/^ROLLBACK/i", $query)) {
482 // Si requete utilisateur, on la sauvegarde ainsi que son resultset
483 if (!is_object($ret) || $this->error) {
484 $this->lastqueryerror = $query;
485 $this->lasterror = $this->error();
486 $this->lasterrno = $this->errno();
487
488 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR);
489
490 $errormsg = get_class($this)."::query SQL Error message: ".$this->lasterror;
491
492 if (preg_match('/[0-9]/', $this->lasterrno)) {
493 $errormsg .= ' ('.$this->lasterrno.')';
494 }
495
496 if ($conf->global->SYSLOG_LEVEL < LOG_DEBUG) {
497 dol_syslog(get_class($this)."::query SQL Error query: ".$query, LOG_ERR); // Log of request was not yet done previously
498 }
499 dol_syslog(get_class($this)."::query SQL Error message: ".$errormsg, LOG_ERR);
500 }
501 $this->lastquery = $query;
502 $this->_results = $ret;
503 }
504
505 return $ret;
506 }
507
508 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
515 public function fetch_object($resultset)
516 {
517 // phpcs:enable
518 // Si le resultset n'est pas fourni, on prend le dernier utilise sur cette connexion
519 if (!is_object($resultset)) {
520 $resultset = $this->_results;
521 }
522 //return $resultset->fetch(PDO::FETCH_OBJ);
523 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
524 if ($ret) {
525 return (object) $ret;
526 }
527 return false;
528 }
529
530
531 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
538 public function fetch_array($resultset)
539 {
540 // phpcs:enable
541 // If resultset not provided, we take the last used by connexion
542 if (!is_object($resultset)) {
543 $resultset = $this->_results;
544 }
545 //return $resultset->fetch(PDO::FETCH_ASSOC);
546 $ret = $resultset->fetchArray(SQLITE3_ASSOC);
547 return $ret;
548 }
549
550 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
557 public function fetch_row($resultset)
558 {
559 // phpcs:enable
560 // If resultset not provided, we take the last used by connexion
561 if (!is_bool($resultset)) {
562 if (!is_object($resultset)) {
563 $resultset = $this->_results;
564 }
565 return $resultset->fetchArray(SQLITE3_NUM);
566 } else {
567 // si le curseur est un booleen on retourne la valeur 0
568 return false;
569 }
570 }
571
572 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
580 public function num_rows($resultset)
581 {
582 // phpcs:enable
583 // FIXME: SQLite3Result does not have a queryString member
584
585 // If resultset not provided, we take the last used by connexion
586 if (!is_object($resultset)) {
587 $resultset = $this->_results;
588 }
589 if (preg_match("/^SELECT/i", $resultset->queryString)) {
590 return $this->db->querySingle("SELECT count(*) FROM (".$resultset->queryString.") q");
591 }
592 return 0;
593 }
594
595 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
603 public function affected_rows($resultset)
604 {
605 // phpcs:enable
606 // FIXME: SQLite3Result does not have a queryString member
607
608 // If resultset not provided, we take the last used by connexion
609 if (!is_object($resultset)) {
610 $resultset = $this->_results;
611 }
612 if (preg_match("/^SELECT/i", $resultset->queryString)) {
613 return $this->num_rows($resultset);
614 }
615 // mysql necessite un link de base pour cette fonction contrairement
616 // a pqsql qui prend un resultset
617 return $this->db->changes();
618 }
619
620
627 public function free($resultset = null)
628 {
629 // If resultset not provided, we take the last used by connexion
630 if (!is_object($resultset)) {
631 $resultset = $this->_results;
632 }
633 // Si resultset en est un, on libere la memoire
634 if ($resultset && is_object($resultset)) {
635 $resultset->finalize();
636 }
637 }
638
645 public function escape($stringtoencode)
646 {
647 return Sqlite3::escapeString($stringtoencode);
648 }
649
656 public function escapeforlike($stringtoencode)
657 {
658 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
659 }
660
666 public function errno()
667 {
668 if (!$this->connected) {
669 // Si il y a eu echec de connexion, $this->db n'est pas valide.
670 return 'DB_ERROR_FAILED_TO_CONNECT';
671 } else {
672 // Constants to convert error code to a generic Dolibarr error code
673 /*$errorcode_map = array(
674 1004 => 'DB_ERROR_CANNOT_CREATE',
675 1005 => 'DB_ERROR_CANNOT_CREATE',
676 1006 => 'DB_ERROR_CANNOT_CREATE',
677 1007 => 'DB_ERROR_ALREADY_EXISTS',
678 1008 => 'DB_ERROR_CANNOT_DROP',
679 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
680 1044 => 'DB_ERROR_ACCESSDENIED',
681 1046 => 'DB_ERROR_NODBSELECTED',
682 1048 => 'DB_ERROR_CONSTRAINT',
683 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
684 1051 => 'DB_ERROR_NOSUCHTABLE',
685 1054 => 'DB_ERROR_NOSUCHFIELD',
686 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
687 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
688 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
689 1064 => 'DB_ERROR_SYNTAX',
690 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
691 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
692 1091 => 'DB_ERROR_NOSUCHFIELD',
693 1100 => 'DB_ERROR_NOT_LOCKED',
694 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
695 1146 => 'DB_ERROR_NOSUCHTABLE',
696 1216 => 'DB_ERROR_NO_PARENT',
697 1217 => 'DB_ERROR_CHILD_EXISTS',
698 1451 => 'DB_ERROR_CHILD_EXISTS'
699 );
700
701 if (isset($errorcode_map[$this->db->errorCode()]))
702 {
703 return $errorcode_map[$this->db->errorCode()];
704 }*/
705 $errno = $this->db->lastErrorCode();
706 if ($errno == 'HY000' || $errno == 0) {
707 if (preg_match('/table.*already exists/i', $this->error)) {
708 return 'DB_ERROR_TABLE_ALREADY_EXISTS';
709 } elseif (preg_match('/index.*already exists/i', $this->error)) {
710 return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
711 } elseif (preg_match('/syntax error/i', $this->error)) {
712 return 'DB_ERROR_SYNTAX';
713 }
714 }
715 if ($errno == '23000') {
716 if (preg_match('/column.* not unique/i', $this->error)) {
717 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
718 } elseif (preg_match('/PRIMARY KEY must be unique/i', $this->error)) {
719 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
720 }
721 }
722 if ($errno > 1) {
723 // TODO Voir la liste des messages d'erreur
724 }
725
726 return ($errno ? 'DB_ERROR_'.$errno : '0');
727 }
728 }
729
735 public function error()
736 {
737 if (!$this->connected) {
738 // Si il y a eu echec de connexion, $this->db n'est pas valide pour sqlite_error.
739 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
740 } else {
741 return $this->error;
742 }
743 }
744
745 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
753 public function last_insert_id($tab, $fieldid = 'rowid')
754 {
755 // phpcs:enable
756 return $this->db->lastInsertRowId();
757 }
758
767 public function encrypt($fieldorvalue, $withQuotes = 1)
768 {
769 global $conf;
770
771 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
772 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
773
774 //Encryption key
775 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
776
777 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
778
779 if ($cryptType && !empty($cryptKey)) {
780 if ($cryptType == 2) {
781 $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
782 } elseif ($cryptType == 1) {
783 $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
784 }
785 }
786
787 return $escapedstringwithquotes;
788 }
789
796 public function decrypt($value)
797 {
798 global $conf;
799
800 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
801 $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
802
803 //Encryption key
804 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
805
806 $return = $value;
807
808 if ($cryptType && !empty($cryptKey)) {
809 if ($cryptType == 2) {
810 $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
811 } elseif ($cryptType == 1) {
812 $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
813 }
814 }
815
816 return $return;
817 }
818
819
820 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
826 public function DDLGetConnectId()
827 {
828 // phpcs:enable
829 return '?';
830 }
831
832
833 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
845 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
846 {
847 // phpcs:enable
848 if (empty($charset)) {
849 $charset = $this->forcecharset;
850 }
851 if (empty($collation)) {
852 $collation = $this->forcecollate;
853 }
854
855 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
856 $sql = "CREATE DATABASE ".$this->escape($database);
857 $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
858
859 dol_syslog($sql, LOG_DEBUG);
860 $ret = $this->query($sql);
861
862 return $ret;
863 }
864
865 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
873 public function DDLListTables($database, $table = '')
874 {
875 // phpcs:enable
876 $listtables = array();
877
878 $like = '';
879 if ($table) {
880 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
881
882 $like = "LIKE '".$this->escape($tmptable)."'";
883 }
884 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
885
886 $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
887 //print $sql;
888 $result = $this->query($sql);
889 if ($result) {
890 while ($row = $this->fetch_row($result)) {
891 $listtables[] = $row[0];
892 }
893 }
894 return $listtables;
895 }
896
897 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
905 public function DDLListTablesFull($database, $table = '')
906 {
907 // phpcs:enable
908 $listtables = array();
909
910 $like = '';
911 if ($table) {
912 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
913
914 $like = "LIKE '".$this->escape($tmptable)."'";
915 }
916 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
917
918 $sql = "SHOW FULL TABLES FROM ".$tmpdatabase." ".$like.";";
919 //print $sql;
920 $result = $this->query($sql);
921 if ($result) {
922 while ($row = $this->fetch_row($result)) {
923 $listtables[] = $row;
924 }
925 }
926 return $listtables;
927 }
928
929 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
937 public function DDLInfoTable($table)
938 {
939 // phpcs:enable
940 $infotables = array();
941
942 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
943
944 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
945
946 dol_syslog($sql, LOG_DEBUG);
947 $result = $this->query($sql);
948 if ($result) {
949 while ($row = $this->fetch_row($result)) {
950 $infotables[] = $row;
951 }
952 }
953 return $infotables;
954 }
955
956 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
969 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
970 {
971 // phpcs:enable
972 // FIXME: $fulltext_keys parameter is unused
973
974 // cles recherchees dans le tableau des descriptions (fields) : type,value,attribute,null,default,extra
975 // ex. : $fields['rowid'] = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
976 $sql = "create table ".$table."(";
977 $i = 0;
978 foreach ($fields as $field_name => $field_desc) {
979 $sqlfields[$i] = $field_name." ";
980 $sqlfields[$i] .= $field_desc['type'];
981 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
982 $sqlfields[$i] .= "(".$field_desc['value'].")";
983 } elseif (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
984 $sqlfields[$i] .= " ".$field_desc['attribute'];
985 } elseif (preg_match("/^[^\s]/i", $field_desc['default'])) {
986 if (preg_match("/null/i", $field_desc['default'])) {
987 $sqlfields[$i] .= " default ".$field_desc['default'];
988 } else {
989 $sqlfields[$i] .= " default '".$this->escape($field_desc['default'])."'";
990 }
991 } elseif (preg_match("/^[^\s]/i", $field_desc['null'])) {
992 $sqlfields[$i] .= " ".$field_desc['null'];
993 } elseif (preg_match("/^[^\s]/i", $field_desc['extra'])) {
994 $sqlfields[$i] .= " ".$field_desc['extra'];
995 }
996 $i++;
997 }
998 if ($primary_key != "") {
999 $pk = "primary key(".$primary_key.")";
1000 }
1001
1002 if (is_array($unique_keys)) {
1003 $i = 0;
1004 foreach ($unique_keys as $key => $value) {
1005 $sqluq[$i] = "UNIQUE KEY '".$key."' ('".$this->escape($value)."')";
1006 $i++;
1007 }
1008 }
1009 if (is_array($keys)) {
1010 $i = 0;
1011 foreach ($keys as $key => $value) {
1012 $sqlk[$i] = "KEY ".$key." (".$value.")";
1013 $i++;
1014 }
1015 }
1016 $sql .= implode(',', $sqlfields);
1017 if ($primary_key != "") {
1018 $sql .= ",".$pk;
1019 }
1020 if (is_array($unique_keys)) {
1021 $sql .= ",".implode(',', $sqluq);
1022 }
1023 if (is_array($keys)) {
1024 $sql .= ",".implode(',', $sqlk);
1025 }
1026 $sql .= ") type=".$type;
1027
1028 dol_syslog($sql, LOG_DEBUG);
1029 if (!$this -> query($sql)) {
1030 return -1;
1031 }
1032 return 1;
1033 }
1034
1035 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1042 public function DDLDropTable($table)
1043 {
1044 // phpcs:enable
1045 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1046
1047 $sql = "DROP TABLE ".$tmptable;
1048
1049 if (!$this->query($sql)) {
1050 return -1;
1051 } else {
1052 return 1;
1053 }
1054 }
1055
1056 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1064 public function DDLDescTable($table, $field = "")
1065 {
1066 // phpcs:enable
1067 $sql = "DESC ".$table." ".$field;
1068
1069 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1070 $this->_results = $this->query($sql);
1071 return $this->_results;
1072 }
1073
1074 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1084 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1085 {
1086 // phpcs:enable
1087 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1088 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1089 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1090 $sql .= $field_desc['type'];
1091 if (preg_match("/^[^\s]/i", $field_desc['value'])) {
1092 if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1093 $sql .= "(".$field_desc['value'].")";
1094 }
1095 }
1096 if (preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1097 $sql .= " ".$field_desc['attribute'];
1098 }
1099 if (preg_match("/^[^\s]/i", $field_desc['null'])) {
1100 $sql .= " ".$field_desc['null'];
1101 }
1102 if (preg_match("/^[^\s]/i", $field_desc['default'])) {
1103 if (preg_match("/null/i", $field_desc['default'])) {
1104 $sql .= " default ".$field_desc['default'];
1105 } else {
1106 $sql .= " default '".$this->escape($field_desc['default'])."'";
1107 }
1108 }
1109 if (preg_match("/^[^\s]/i", $field_desc['extra'])) {
1110 $sql .= " ".$field_desc['extra'];
1111 }
1112 $sql .= " ".$field_position;
1113
1114 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1115 if (!$this->query($sql)) {
1116 return -1;
1117 }
1118 return 1;
1119 }
1120
1121 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1130 public function DDLUpdateField($table, $field_name, $field_desc)
1131 {
1132 // phpcs:enable
1133 $sql = "ALTER TABLE ".$table;
1134 $sql .= " MODIFY COLUMN ".$field_name." ".$field_desc['type'];
1135 if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1136 $sql .= "(".$field_desc['value'].")";
1137 }
1138
1139 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1140 if (!$this->query($sql)) {
1141 return -1;
1142 }
1143 return 1;
1144 }
1145
1146 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1154 public function DDLDropField($table, $field_name)
1155 {
1156 // phpcs:enable
1157 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1158
1159 $sql = "ALTER TABLE ".$table." DROP COLUMN `".$tmp_field_name."`";
1160 if (!$this->query($sql)) {
1161 $this->error = $this->lasterror();
1162 return -1;
1163 }
1164 return 1;
1165 }
1166
1167
1168 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1178 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1179 {
1180 // phpcs:enable
1181 $sql = "INSERT INTO user ";
1182 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1183 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1184 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1185
1186 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1187 $resql = $this->query($sql);
1188 if (!$resql) {
1189 return -1;
1190 }
1191
1192 $sql = "INSERT INTO db ";
1193 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1194 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1195 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1196
1197 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1198 $resql = $this->query($sql);
1199 if (!$resql) {
1200 return -1;
1201 }
1202
1203 $sql = "FLUSH Privileges";
1204
1205 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1206 $resql = $this->query($sql);
1207 if (!$resql) {
1208 return -1;
1209 }
1210 return 1;
1211 }
1212
1218 public function getDefaultCharacterSetDatabase()
1219 {
1220 return 'UTF-8';
1221 }
1222
1228 public function getListOfCharacterSet()
1229 {
1230 $liste = array();
1231 $i = 0;
1232 $liste[$i]['charset'] = 'UTF-8';
1233 $liste[$i]['description'] = 'UTF-8';
1234 return $liste;
1235 }
1236
1242 public function getDefaultCollationDatabase()
1243 {
1244 return 'UTF-8';
1245 }
1246
1252 public function getListOfCollation()
1253 {
1254 $liste = array();
1255 $i = 0;
1256 $liste[$i]['charset'] = 'UTF-8';
1257 $liste[$i]['description'] = 'UTF-8';
1258 return $liste;
1259 }
1260
1266 public function getPathOfDump()
1267 {
1268 // FIXME: not for SQLite
1269 $fullpathofdump = '/pathtomysqldump/mysqldump';
1270
1271 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1272 if ($resql) {
1273 $liste = $this->fetch_array($resql);
1274 $basedir = $liste['Value'];
1275 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1276 }
1277 return $fullpathofdump;
1278 }
1279
1285 public function getPathOfRestore()
1286 {
1287 // FIXME: not for SQLite
1288 $fullpathofimport = '/pathtomysql/mysql';
1289
1290 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1291 if ($resql) {
1292 $liste = $this->fetch_array($resql);
1293 $basedir = $liste['Value'];
1294 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1295 }
1296 return $fullpathofimport;
1297 }
1298
1305 public function getServerParametersValues($filter = '')
1306 {
1307 $result = array();
1308 static $pragmas;
1309 if (!isset($pragmas)) {
1310 // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1311 // indépendante de la base de données.
1312 // cf. http://www.sqlite.org/pragma.html
1313 $pragmas = array(
1314 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1315 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1316 'compile_options', 'data_version', /*'database_list',*/
1317 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1318 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1319 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1320 'max_page_count', 'page_count', 'page_size', 'parser_trace',
1321 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1322 'reverse_unordered_selects', 'schema_version', 'user_version',
1323 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1324 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1325 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1326 'wal_autocheckpoint',
1327 );
1328 }
1329
1330 // TODO prendre en compte le filtre
1331 foreach ($pragmas as $var) {
1332 $sql = "PRAGMA $var";
1333 $resql = $this->query($sql);
1334 if ($resql) {
1335 $obj = $this->fetch_row($resql);
1336 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1337 $result[$var] = $obj[0];
1338 } else {
1339 // TODO Récupérer le message
1340 $result[$var] = 'FAIL';
1341 }
1342 }
1343 return $result;
1344 }
1345
1352 public function getServerStatusValues($filter = '')
1353 {
1354 $result = array();
1355 /*
1356 $sql='SHOW STATUS';
1357 if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1358 $resql=$this->query($sql);
1359 if ($resql)
1360 {
1361 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1362 }
1363 */
1364
1365 return $result;
1366 }
1367
1377 private function addCustomFunction($name, $arg_count = -1)
1378 {
1379 if ($this->db) {
1380 $newname = preg_replace('/_/', '', $name);
1381 $localname = __CLASS__.'::db'.$newname;
1382 $reflectClass = new ReflectionClass(__CLASS__);
1383 $reflectFunction = $reflectClass->getMethod('db'.$newname);
1384 if ($arg_count < 0) {
1385 $arg_count = $reflectFunction->getNumberOfParameters();
1386 }
1387 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1388 $this->error = "unable to create custom function '$name'";
1389 }
1390 }
1391 }
1392
1393 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1402 private static function calc_daynr($year, $month, $day)
1403 {
1404 // phpcs:enable
1405 $y = $year;
1406 if ($y == 0 && $month == 0) {
1407 return 0;
1408 }
1409 $num = (365 * $y + 31 * ($month - 1) + $day);
1410 if ($month <= 2) {
1411 $y--;
1412 } else {
1413 $num -= floor(($month * 4 + 23) / 10);
1414 }
1415 $temp = floor(($y / 100 + 1) * 3 / 4);
1416 return $num + floor($y / 4) - $temp;
1417 }
1418
1419 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1427 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1428 {
1429 // phpcs:enable
1430 $ret = floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1431 return $ret;
1432 }
1433
1434 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1441 private static function calc_days_in_year($year)
1442 {
1443 // phpcs:enable
1444 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1445 }
1446
1447 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1458 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1459 {
1460 // phpcs:enable
1461 $daynr = self::calc_daynr($year, $month, $day);
1462 $first_daynr = self::calc_daynr($year, 1, 1);
1463 $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1464 $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1465 $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1466
1467 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1468 $calc_year = $year;
1469
1470 if ($month == 1 && $day <= 7 - $weekday) {
1471 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1472 return 0;
1473 }
1474 $week_year = 1;
1475 $calc_year--;
1476 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1477 $weekday = ($weekday + 53 * 7 - $days) % 7;
1478 }
1479
1480 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1481 $days = $daynr - ($first_daynr + (7 - $weekday));
1482 } else {
1483 $days = $daynr - ($first_daynr - $weekday);
1484 }
1485
1486 if ($week_year && $days >= 52 * 7) {
1487 $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1488 if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1489 $calc_year++;
1490 return 1;
1491 }
1492 }
1493 return floor($days / 7 + 1);
1494 }
1495}
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 connexion.
static calc_days_in_year($year)
calc_days_in_year
static calc_daynr($year, $month, $day)
calc_daynr
escapeforlike($stringtoencode)
Escape a string to insert data into a like.
static calc_weekday($daynr, $sunday_first_day_of_week)
calc_weekday
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.
static calc_week($year, $month, $day, $week_behaviour, &$calc_year)
calc_week
getDriverInfo()
Return version of database client driver.
addCustomFunction($name, $arg_count=-1)
Permet le chargement d'une fonction personnalisee dans le moteur de base de donnees.
select_db($database)
Select a database.
connect($host, $login, $passwd, $name, $port=0)
Connexion 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.
publicphonebutton2 phonegreen basiclayout basiclayout TotalHT VATCode TotalVAT TotalLT1 TotalLT2 TotalTTC TotalHT clearboth nowraponall right right takeposterminal SELECT e rowid
Definition invoice.php:1926
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:121