dolibarr 21.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 MDW <mdeweerd@users.noreply.github.com>
9 * Copyright (C) 2024 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)
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 // Pour l'instant les contraintes ne sont pas créées
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 "Resultat fonction connect: ".$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 // Ajout d'une clef étrangère à la table
421 // procédure de replacement de la table pour ajouter la contrainte
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- Renommer la table avec un nom temporaire
433 $this->query("ALTER TABLE ".$tablename." RENAME TO tmp_".$tablename);
434
435 // 2- Recréer la table avec la contrainte ajoutée
436
437 // on bricole la requete pour ajouter la contrainte
438 $descTable = substr($descTable, 0, strlen($descTable) - 1);
439 $descTable .= ", CONSTRAINT ".$constraintname." FOREIGN KEY (".$localfields.") REFERENCES ".$foreignTable."(".$foreignFields.")";
440
441 // fermeture de l'instruction
442 $descTable .= ')';
443
444 // Création proprement dite de la table
445 $this->query($descTable);
446
447 // 3- Transférer les données
448 $this->query("INSERT INTO ".$tablename." SELECT * FROM tmp_".$tablename);
449
450 // 4- Supprimer la table temporaire
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 ($conf->global->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 // si le curseur est un boolean on retourne la valeur 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 necessite un link de base pour cette fonction contrairement
623 // a pqsql qui prend un resultset
624 return $this->db->changes();
625 }
626
627
634 public function free($resultset = null)
635 {
636 // If resultset not provided, we take the last used by connection
637 if (!is_object($resultset)) {
638 $resultset = $this->_results;
639 }
640 // Si resultset en est un, on libere la memoire
641 if ($resultset && is_object($resultset)) {
642 $resultset->finalize();
643 }
644 }
645
652 public function escape($stringtoencode)
653 {
654 return Sqlite3::escapeString($stringtoencode);
655 }
656
663 public function escapeforlike($stringtoencode)
664 {
665 return str_replace(array('\\', '_', '%'), array('\\\\', '\_', '\%'), (string) $stringtoencode);
666 }
667
673 public function errno()
674 {
675 if (!$this->connected) {
676 // Si il y a eu echec de connection, $this->db n'est pas valide.
677 return 'DB_ERROR_FAILED_TO_CONNECT';
678 } else {
679 // Constants to convert error code to a generic Dolibarr error code
680 /*$errorcode_map = array(
681 1004 => 'DB_ERROR_CANNOT_CREATE',
682 1005 => 'DB_ERROR_CANNOT_CREATE',
683 1006 => 'DB_ERROR_CANNOT_CREATE',
684 1007 => 'DB_ERROR_ALREADY_EXISTS',
685 1008 => 'DB_ERROR_CANNOT_DROP',
686 1025 => 'DB_ERROR_NO_FOREIGN_KEY_TO_DROP',
687 1044 => 'DB_ERROR_ACCESSDENIED',
688 1046 => 'DB_ERROR_NODBSELECTED',
689 1048 => 'DB_ERROR_CONSTRAINT',
690 'HY000' => 'DB_ERROR_TABLE_ALREADY_EXISTS',
691 1051 => 'DB_ERROR_NOSUCHTABLE',
692 1054 => 'DB_ERROR_NOSUCHFIELD',
693 1060 => 'DB_ERROR_COLUMN_ALREADY_EXISTS',
694 1061 => 'DB_ERROR_KEY_NAME_ALREADY_EXISTS',
695 1062 => 'DB_ERROR_RECORD_ALREADY_EXISTS',
696 1064 => 'DB_ERROR_SYNTAX',
697 1068 => 'DB_ERROR_PRIMARY_KEY_ALREADY_EXISTS',
698 1075 => 'DB_ERROR_CANT_DROP_PRIMARY_KEY',
699 1091 => 'DB_ERROR_NOSUCHFIELD',
700 1100 => 'DB_ERROR_NOT_LOCKED',
701 1136 => 'DB_ERROR_VALUE_COUNT_ON_ROW',
702 1146 => 'DB_ERROR_NOSUCHTABLE',
703 1216 => 'DB_ERROR_NO_PARENT',
704 1217 => 'DB_ERROR_CHILD_EXISTS',
705 1451 => 'DB_ERROR_CHILD_EXISTS'
706 );
707
708 if (isset($errorcode_map[$this->db->errorCode()]))
709 {
710 return $errorcode_map[$this->db->errorCode()];
711 }*/
712 $errno = $this->db->lastErrorCode();
713 if ($errno == 'HY000' || $errno == 0) {
714 if (preg_match('/table.*already exists/i', $this->error)) {
715 return 'DB_ERROR_TABLE_ALREADY_EXISTS';
716 } elseif (preg_match('/index.*already exists/i', $this->error)) {
717 return 'DB_ERROR_KEY_NAME_ALREADY_EXISTS';
718 } elseif (preg_match('/syntax error/i', $this->error)) {
719 return 'DB_ERROR_SYNTAX';
720 }
721 }
722 if ($errno == '23000') {
723 if (preg_match('/column.* not unique/i', $this->error)) {
724 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
725 } elseif (preg_match('/PRIMARY KEY must be unique/i', $this->error)) {
726 return 'DB_ERROR_RECORD_ALREADY_EXISTS';
727 }
728 }
729 if ($errno > 1) {
730 // TODO Voir la liste des messages d'erreur
731 }
732
733 return ($errno ? 'DB_ERROR_'.$errno : '0');
734 }
735 }
736
742 public function error()
743 {
744 if (!$this->connected) {
745 // Si il y a eu echec de connection, $this->db n'est pas valide pour sqlite_error.
746 return 'Not connected. Check setup parameters in conf/conf.php file and your sqlite version';
747 } else {
748 return $this->error;
749 }
750 }
751
752 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
760 public function last_insert_id($tab, $fieldid = 'rowid')
761 {
762 // phpcs:enable
763 return $this->db->lastInsertRowId();
764 }
765
774 public function encrypt($fieldorvalue, $withQuotes = 1)
775 {
776 global $conf;
777
778 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
779 $cryptType = (!empty($conf->db->dolibarr_main_db_encryption) ? $conf->db->dolibarr_main_db_encryption : 0);
780
781 //Encryption key
782 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
783
784 $escapedstringwithquotes = ($withQuotes ? "'" : "").$this->escape($fieldorvalue).($withQuotes ? "'" : "");
785
786 if ($cryptType && !empty($cryptKey)) {
787 if ($cryptType == 2) {
788 $escapedstringwithquotes = "AES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
789 } elseif ($cryptType == 1) {
790 $escapedstringwithquotes = "DES_ENCRYPT(".$escapedstringwithquotes.", '".$this->escape($cryptKey)."')";
791 }
792 }
793
794 return $escapedstringwithquotes;
795 }
796
803 public function decrypt($value)
804 {
805 global $conf;
806
807 // Type of encryption (2: AES (recommended), 1: DES , 0: no encryption)
808 $cryptType = ($conf->db->dolibarr_main_db_encryption ? $conf->db->dolibarr_main_db_encryption : 0);
809
810 //Encryption key
811 $cryptKey = (!empty($conf->db->dolibarr_main_db_cryptkey) ? $conf->db->dolibarr_main_db_cryptkey : '');
812
813 $return = $value;
814
815 if ($cryptType && !empty($cryptKey)) {
816 if ($cryptType == 2) {
817 $return = 'AES_DECRYPT('.$value.',\''.$cryptKey.'\')';
818 } elseif ($cryptType == 1) {
819 $return = 'DES_DECRYPT('.$value.',\''.$cryptKey.'\')';
820 }
821 }
822
823 return $return;
824 }
825
826
827 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
833 public function DDLGetConnectId()
834 {
835 // phpcs:enable
836 return '?';
837 }
838
839
840 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
852 public function DDLCreateDb($database, $charset = '', $collation = '', $owner = '')
853 {
854 // phpcs:enable
855 if (empty($charset)) {
856 $charset = $this->forcecharset;
857 }
858 if (empty($collation)) {
859 $collation = $this->forcecollate;
860 }
861
862 // ALTER DATABASE dolibarr_db DEFAULT CHARACTER SET latin DEFAULT COLLATE latin1_swedish_ci
863 $sql = "CREATE DATABASE ".$this->escape($database);
864 $sql .= " DEFAULT CHARACTER SET ".$this->escape($charset)." DEFAULT COLLATE ".$this->escape($collation);
865
866 dol_syslog($sql, LOG_DEBUG);
867 $ret = $this->query($sql);
868
869 return $ret;
870 }
871
872 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
880 public function DDLListTables($database, $table = '')
881 {
882 // phpcs:enable
883 $listtables = array();
884
885 $like = '';
886 if ($table) {
887 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
888
889 $like = "LIKE '".$this->escape($tmptable)."'";
890 }
891 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
892
893 $sql = "SHOW TABLES FROM ".$tmpdatabase." ".$like.";";
894 //print $sql;
895 $result = $this->query($sql);
896 if ($result) {
897 while ($row = $this->fetch_row($result)) {
898 $listtables[] = $row[0];
899 }
900 }
901 return $listtables;
902 }
903
904 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
912 public function DDLListTablesFull($database, $table = '')
913 {
914 // phpcs:enable
915 $listtables = array();
916
917 $like = '';
918 if ($table) {
919 $tmptable = preg_replace('/[^a-z0-9\.\-\_%]/i', '', $table);
920
921 $like = "LIKE '".$this->escape($tmptable)."'";
922 }
923 $tmpdatabase = preg_replace('/[^a-z0-9\.\-\_]/i', '', $database);
924
925 $sql = "SHOW FULL TABLES FROM ".$tmpdatabase." ".$like.";";
926 //print $sql;
927 $result = $this->query($sql);
928 if ($result) {
929 while ($row = $this->fetch_row($result)) {
930 $listtables[] = $row;
931 }
932 }
933 return $listtables;
934 }
935
936 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
945 public function DDLInfoTable($table)
946 {
947 // phpcs:enable
948 $infotables = array();
949
950 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
951
952 $sql = "SHOW FULL COLUMNS FROM ".$tmptable.";";
953
954 dol_syslog($sql, LOG_DEBUG);
955 $result = $this->query($sql);
956 if ($result) {
957 while ($row = $this->fetch_row($result)) {
958 $infotables[] = $row;
959 }
960 }
961 return $infotables;
962 }
963
964 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
977 public function DDLCreateTable($table, $fields, $primary_key, $type, $unique_keys = null, $fulltext_keys = null, $keys = null)
978 {
979 // phpcs:enable
980 // @TODO: $fulltext_keys parameter is unused
981
982 $sqlk = array();
983 $sqluq = array();
984
985 // Keys found into the array $fields: type,value,attribute,null,default,extra
986 // ex. : $fields['rowid'] = array(
987 // 'type'=>'int' or 'integer',
988 // 'value'=>'11',
989 // 'null'=>'not null',
990 // 'extra'=> 'auto_increment'
991 // );
992 $sql = "CREATE TABLE ".$this->sanitize($table)."(";
993 $i = 0;
994 $sqlfields = array();
995 foreach ($fields as $field_name => $field_desc) {
996 $sqlfields[$i] = $this->sanitize($field_name)." ";
997 $sqlfields[$i] .= $this->sanitize($field_desc['type']);
998 if (!is_null($field_desc['value']) && $field_desc['value'] !== '') {
999 $sqlfields[$i] .= "(".$this->sanitize($field_desc['value']).")";
1000 }
1001 if (!is_null($field_desc['attribute']) && $field_desc['attribute'] !== '') {
1002 $sqlfields[$i] .= " ".$this->sanitize($field_desc['attribute']);
1003 }
1004 if (!is_null($field_desc['default']) && $field_desc['default'] !== '') {
1005 if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
1006 $sqlfields[$i] .= " DEFAULT ".((float) $field_desc['default']);
1007 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
1008 $sqlfields[$i] .= " DEFAULT ".$this->sanitize($field_desc['default']);
1009 } else {
1010 $sqlfields[$i] .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1011 }
1012 }
1013 if (!is_null($field_desc['null']) && $field_desc['null'] !== '') {
1014 $sqlfields[$i] .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1015 }
1016 if (!is_null($field_desc['extra']) && $field_desc['extra'] !== '') {
1017 $sqlfields[$i] .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1018 }
1019 $i++;
1020 }
1021 if ($primary_key != "") {
1022 $pk = "PRIMARY KEY(".$this->sanitize($primary_key).")";
1023 } else {
1024 $pk = "";
1025 }
1026
1027
1028 if (is_array($unique_keys)) {
1029 $i = 0;
1030 foreach ($unique_keys as $key => $value) {
1031 $sqluq[$i] = "UNIQUE KEY '".$this->sanitize($key)."' ('".$this->escape($value)."')";
1032 $i++;
1033 }
1034 }
1035 if (is_array($keys)) {
1036 $i = 0;
1037 foreach ($keys as $key => $value) {
1038 $sqlk[$i] = "KEY ".$this->sanitize($key)." (".$value.")";
1039 $i++;
1040 }
1041 }
1042 $sql .= implode(',', $sqlfields);
1043 if ($primary_key != "") {
1044 $sql .= ",".$pk;
1045 }
1046 if ($unique_keys != "") {
1047 $sql .= ",".implode(',', $sqluq);
1048 }
1049 if (is_array($keys)) {
1050 $sql .= ",".implode(',', $sqlk);
1051 }
1052 $sql .= ")";
1053 //$sql .= " engine=".$this->sanitize($type);
1054
1055 if (!$this->query($sql)) {
1056 return -1;
1057 } else {
1058 return 1;
1059 }
1060 }
1061
1062 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1069 public function DDLDropTable($table)
1070 {
1071 // phpcs:enable
1072 $tmptable = preg_replace('/[^a-z0-9\.\-\_]/i', '', $table);
1073
1074 $sql = "DROP TABLE ".$tmptable;
1075
1076 if (!$this->query($sql)) {
1077 return -1;
1078 } else {
1079 return 1;
1080 }
1081 }
1082
1083 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1091 public function DDLDescTable($table, $field = "")
1092 {
1093 // phpcs:enable
1094 $sql = "DESC ".$table." ".$field;
1095
1096 dol_syslog(get_class($this)."::DDLDescTable ".$sql, LOG_DEBUG);
1097 $this->_results = $this->query($sql);
1098 return $this->_results;
1099 }
1100
1101 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1111 public function DDLAddField($table, $field_name, $field_desc, $field_position = "")
1112 {
1113 // phpcs:enable
1114 // cles recherchees dans le tableau des descriptions (field_desc) : type,value,attribute,null,default,extra
1115 // ex. : $field_desc = array('type'=>'int','value'=>'11','null'=>'not null','extra'=> 'auto_increment');
1116 $sql = "ALTER TABLE ".$table." ADD ".$field_name." ";
1117 $sql .= $field_desc['type'];
1118 if (isset($field_desc['value']) && preg_match("/^[^\s]/i", $field_desc['value'])) {
1119 if (!in_array($field_desc['type'], array('date', 'datetime'))) {
1120 $sql .= "(".$field_desc['value'].")";
1121 }
1122 }
1123 if (isset($field_desc['attribute']) && preg_match("/^[^\s]/i", $field_desc['attribute'])) {
1124 $sql .= " ".$this->sanitize($field_desc['attribute']);
1125 }
1126 if (isset($field_desc['null']) && preg_match("/^[^\s]/i", $field_desc['null'])) {
1127 $sql .= " ".$this->sanitize($field_desc['null'], 0, 0, 1);
1128 }
1129 if (isset($field_desc['default']) && preg_match("/^[^\s]/i", $field_desc['default'])) {
1130 if (in_array($field_desc['type'], array('tinyint', 'smallint', 'int', 'double'))) {
1131 $sql .= " DEFAULT ".((float) $field_desc['default']);
1132 } elseif ($field_desc['default'] == 'null' || $field_desc['default'] == 'CURRENT_TIMESTAMP') {
1133 $sql .= " DEFAULT ".$this->sanitize($field_desc['default']);
1134 } else {
1135 $sql .= " DEFAULT '".$this->escape($field_desc['default'])."'";
1136 }
1137 }
1138 if (isset($field_desc['extra']) && preg_match("/^[^\s]/i", $field_desc['extra'])) {
1139 $sql .= " ".$this->sanitize($field_desc['extra'], 0, 0, 1);
1140 }
1141 $sql .= " ".$this->sanitize($field_position, 0, 0, 1);
1142
1143 dol_syslog(get_class($this)."::DDLAddField ".$sql, LOG_DEBUG);
1144 if (!$this->query($sql)) {
1145 return -1;
1146 }
1147 return 1;
1148 }
1149
1150 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1159 public function DDLUpdateField($table, $field_name, $field_desc)
1160 {
1161 // phpcs:enable
1162 $sql = "ALTER TABLE ".$this->sanitize($table);
1163 $sql .= " MODIFY COLUMN ".$this->sanitize($field_name)." ".$this->sanitize($field_desc['type']);
1164 if ($field_desc['type'] == 'tinyint' || $field_desc['type'] == 'int' || $field_desc['type'] == 'varchar') {
1165 $sql .= "(".$this->sanitize($field_desc['value']).")";
1166 }
1167
1168 dol_syslog(get_class($this)."::DDLUpdateField ".$sql, LOG_DEBUG);
1169 if (!$this->query($sql)) {
1170 return -1;
1171 }
1172 return 1;
1173 }
1174
1175 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1183 public function DDLDropField($table, $field_name)
1184 {
1185 // phpcs:enable
1186 $tmp_field_name = preg_replace('/[^a-z0-9\.\-\_]/i', '', $field_name);
1187
1188 $sql = "ALTER TABLE ".$this->sanitize($table)." DROP COLUMN `".$this->sanitize($tmp_field_name)."`";
1189 if (!$this->query($sql)) {
1190 $this->error = $this->lasterror();
1191 return -1;
1192 }
1193 return 1;
1194 }
1195
1196
1197 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1207 public function DDLCreateUser($dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_pass, $dolibarr_main_db_name)
1208 {
1209 // phpcs:enable
1210 $sql = "INSERT INTO user ";
1211 $sql .= "(Host,User,password,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1212 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_user)."',password('".addslashes($dolibarr_main_db_pass)."')";
1213 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1214
1215 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG); // No sql to avoid password in log
1216 $resql = $this->query($sql);
1217 if (!$resql) {
1218 return -1;
1219 }
1220
1221 $sql = "INSERT INTO db ";
1222 $sql .= "(Host,Db,User,Select_priv,Insert_priv,Update_priv,Delete_priv,Create_priv,Drop_priv,Index_Priv,Alter_priv,Lock_tables_priv)";
1223 $sql .= " VALUES ('".$this->escape($dolibarr_main_db_host)."','".$this->escape($dolibarr_main_db_name)."','".addslashes($dolibarr_main_db_user)."'";
1224 $sql .= ",'Y','Y','Y','Y','Y','Y','Y','Y','Y')";
1225
1226 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1227 $resql = $this->query($sql);
1228 if (!$resql) {
1229 return -1;
1230 }
1231
1232 $sql = "FLUSH Privileges";
1233
1234 dol_syslog(get_class($this)."::DDLCreateUser", LOG_DEBUG);
1235 $resql = $this->query($sql);
1236 if (!$resql) {
1237 return -1;
1238 }
1239 return 1;
1240 }
1241
1247 public function getDefaultCharacterSetDatabase()
1248 {
1249 return 'UTF-8';
1250 }
1251
1257 public function getListOfCharacterSet()
1258 {
1259 $liste = array();
1260 $i = 0;
1261 $liste[$i]['charset'] = 'UTF-8';
1262 $liste[$i]['description'] = 'UTF-8';
1263 return $liste;
1264 }
1265
1271 public function getDefaultCollationDatabase()
1272 {
1273 return 'UTF-8';
1274 }
1275
1281 public function getListOfCollation()
1282 {
1283 $liste = array();
1284 $i = 0;
1285 $liste[$i]['charset'] = 'UTF-8';
1286 $liste[$i]['description'] = 'UTF-8';
1287 return $liste;
1288 }
1289
1295 public function getPathOfDump()
1296 {
1297 // FIXME: not for SQLite
1298 $fullpathofdump = '/pathtomysqldump/mysqldump';
1299
1300 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1301 if ($resql) {
1302 $liste = $this->fetch_array($resql);
1303 $basedir = $liste['Value'];
1304 $fullpathofdump = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysqldump';
1305 }
1306 return $fullpathofdump;
1307 }
1308
1314 public function getPathOfRestore()
1315 {
1316 // FIXME: not for SQLite
1317 $fullpathofimport = '/pathtomysql/mysql';
1318
1319 $resql = $this->query('SHOW VARIABLES LIKE \'basedir\'');
1320 if ($resql) {
1321 $liste = $this->fetch_array($resql);
1322 $basedir = $liste['Value'];
1323 $fullpathofimport = $basedir.(preg_match('/\/$/', $basedir) ? '' : '/').'bin/mysql';
1324 }
1325 return $fullpathofimport;
1326 }
1327
1334 public function getServerParametersValues($filter = '')
1335 {
1336 $result = array();
1337 static $pragmas;
1338 if (!isset($pragmas)) {
1339 // Définition de la liste des pragmas utilisés qui ne retournent qu'une seule valeur
1340 // indépendante de la base de données.
1341 // cf. http://www.sqlite.org/pragma.html
1342 $pragmas = array(
1343 'application_id', 'auto_vacuum', 'automatic_index', 'busy_timeout', 'cache_size',
1344 'cache_spill', 'case_sensitive_like', 'checkpoint_fullsync', 'collation_list',
1345 'compile_options', 'data_version', /*'database_list',*/
1346 'defer_foreign_keys', 'encoding', 'foreign_key_check', 'freelist_count',
1347 'full_column_names', 'fullsync', 'ingore_check_constraints', 'integrity_check',
1348 'journal_mode', 'journal_size_limit', 'legacy_file_format', 'locking_mode',
1349 'max_page_count', 'page_count', 'page_size', 'parser_trace',
1350 'query_only', 'quick_check', 'read_uncommitted', 'recursive_triggers',
1351 'reverse_unordered_selects', 'schema_version', 'user_version',
1352 'secure_delete', 'short_column_names', 'shrink_memory', 'soft_heap_limit',
1353 'synchronous', 'temp_store', /*'temp_store_directory',*/ 'threads',
1354 'vdbe_addoptrace', 'vdbe_debug', 'vdbe_listing', 'vdbe_trace',
1355 'wal_autocheckpoint',
1356 );
1357 }
1358
1359 // TODO prendre en compte le filtre
1360 foreach ($pragmas as $var) {
1361 $sql = "PRAGMA $var";
1362 $resql = $this->query($sql);
1363 if ($resql) {
1364 $obj = $this->fetch_row($resql);
1365 //dol_syslog(get_class($this)."::select_db getServerParametersValues $var=". print_r($obj, true), LOG_DEBUG);
1366 $result[$var] = $obj[0];
1367 } else {
1368 // TODO Récupérer le message
1369 $result[$var] = 'FAIL';
1370 }
1371 }
1372 return $result;
1373 }
1374
1381 public function getServerStatusValues($filter = '')
1382 {
1383 $result = array();
1384 /*
1385 $sql='SHOW STATUS';
1386 if ($filter) $sql.=" LIKE '".$this->escape($filter)."'";
1387 $resql=$this->query($sql);
1388 if ($resql)
1389 {
1390 while ($obj=$this->fetch_object($resql)) $result[$obj->Variable_name]=$obj->Value;
1391 }
1392 */
1393
1394 return $result;
1395 }
1396
1408 private function addCustomFunction($name, $arg_count = -1)
1409 {
1410 if ($this->db) {
1411 $newname = preg_replace('/_/', '', $name);
1412 $localname = __CLASS__.'::db'.$newname;
1413 $reflectClass = new ReflectionClass(__CLASS__);
1414 $reflectFunction = $reflectClass->getMethod('db'.$newname);
1415 if ($arg_count < 0) {
1416 $arg_count = $reflectFunction->getNumberOfParameters();
1417 }
1418 if (!$this->db->createFunction($name, $localname, $arg_count)) {
1419 $this->error = "unable to create custom function '$name'";
1420 }
1421 }
1422 }
1423
1424 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1425 /* Unused/commented
1426 * calc_daynr
1427 *
1428 * param int $year Year
1429 * param int $month Month
1430 * param int $day Day
1431 * return int Formatted date
1432 */
1433 /*
1434 private static function calc_daynr($year, $month, $day)
1435 {
1436 // phpcs:enable
1437 $y = $year;
1438 if ($y == 0 && $month == 0) {
1439 return 0;
1440 }
1441 $num = (365 * $y + 31 * ($month - 1) + $day);
1442 if ($month <= 2) {
1443 $y--;
1444 } else {
1445 $num -= floor(($month * 4 + 23) / 10);
1446 }
1447 $temp = floor(($y / 100 + 1) * 3 / 4);
1448 return (int) ($num + floor($y / 4) - $temp);
1449 }
1450 */
1451
1452 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1453 /* Unused/commented
1454 * calc_weekday
1455 *
1456 * param int $daynr ???
1457 * param bool $sunday_first_day_of_week ???
1458 * return int
1459 */
1460 /*
1461 private static function calc_weekday($daynr, $sunday_first_day_of_week)
1462 {
1463 // phpcs:enable
1464 $ret = (int) floor(($daynr + 5 + ($sunday_first_day_of_week ? 1 : 0)) % 7);
1465 return $ret;
1466 }
1467 */
1468
1469 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1470 /* Unused/commented
1471 * calc_days_in_year
1472 *
1473 * param int $year Year
1474 * return int Nb of days in year
1475 */
1476 /*
1477 private static function calc_days_in_year($year)
1478 {
1479 // phpcs:enable
1480 return (($year & 3) == 0 && ($year % 100 || ($year % 400 == 0 && $year)) ? 366 : 365);
1481 }
1482 */
1483
1484 // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
1485 /* Unused/commented
1486 * calc_week
1487 *
1488 * param int $year Year
1489 * param int $month Month
1490 * param int $day Day
1491 * param int $week_behaviour Week behaviour, bit masks: WEEK_MONDAY_FIRST, WEEK_YEAR, WEEK_FIRST_WEEKDAY
1492 * param int $calc_year ??? Year where the week started
1493 * return int ??? Week number in year
1494 */
1495 /*
1496 private static function calc_week($year, $month, $day, $week_behaviour, &$calc_year)
1497 {
1498 // phpcs:enable
1499 $daynr = self::calc_daynr($year, $month, $day);
1500 $first_daynr = self::calc_daynr($year, 1, 1);
1501 $monday_first = ($week_behaviour & self::WEEK_MONDAY_FIRST) ? 1 : 0;
1502 $week_year = ($week_behaviour & self::WEEK_YEAR) ? 1 : 0;
1503 $first_weekday = ($week_behaviour & self::WEEK_FIRST_WEEKDAY) ? 1 : 0;
1504
1505 $weekday = self::calc_weekday($first_daynr, !$monday_first);
1506 $calc_year = $year;
1507
1508 if ($month == 1 && $day <= 7 - $weekday) {
1509 if (!$week_year && (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4))) {
1510 return 0;
1511 }
1512 $week_year = 1;
1513 $calc_year--;
1514 $first_daynr -= ($days = self::calc_days_in_year($calc_year));
1515 $weekday = ($weekday + 53 * 7 - $days) % 7;
1516 }
1517
1518 if (($first_weekday && $weekday != 0) || (!$first_weekday && $weekday >= 4)) {
1519 $days = $daynr - ($first_daynr + (7 - $weekday));
1520 } else {
1521 $days = $daynr - ($first_daynr - $weekday);
1522 }
1523
1524 if ($week_year && $days >= 52 * 7) {
1525 $weekday = ($weekday + self::calc_days_in_year($calc_year)) % 7;
1526 if ((!$first_weekday && $weekday < 4) || ($first_weekday && $weekday == 0)) {
1527 $calc_year++;
1528 return 1;
1529 }
1530 }
1531 return (int) floor($days / 7 + 1);
1532 }
1533 */
1534}
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.
global $conf
The following vars must be defined: $type2label $form $conf, $lang, The following vars may also be de...
Definition member.php:79
if(preg_match('/crypted:/i', $dolibarr_main_db_pass)||!empty($dolibarr_main_db_encrypted_pass)) $conf db type
Definition repair.php:149