Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
57.97% |
291 / 502 |
|
31.25% |
10 / 32 |
CRAP | |
0.00% |
0 / 1 |
SeedDMS_Core_DatabaseAccess | |
57.97% |
291 / 502 |
|
31.25% |
10 / 32 |
3139.64 | |
0.00% |
0 / 1 |
TableList | |
62.50% |
10 / 16 |
|
0.00% |
0 / 1 |
7.90 | |||
hasTable | |
53.33% |
8 / 15 |
|
0.00% |
0 / 1 |
9.66 | |||
ViewList | |
62.50% |
10 / 16 |
|
0.00% |
0 / 1 |
7.90 | |||
__construct | |
82.61% |
19 / 23 |
|
0.00% |
0 / 1 |
4.08 | |||
getDriver | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
useViews | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__destruct | |
33.33% |
1 / 3 |
|
0.00% |
0 / 1 |
5.67 | |||
setLogFp | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
connect | |
59.38% |
19 / 32 |
|
0.00% |
0 / 1 |
27.14 | |||
ensureConnected | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
2 | |||
qstr | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
rbt | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
concat | |
55.56% |
5 / 9 |
|
0.00% |
0 / 1 |
5.40 | |||
getResultArray | |
76.92% |
10 / 13 |
|
0.00% |
0 / 1 |
7.60 | |||
getResult | |
63.64% |
7 / 11 |
|
0.00% |
0 / 1 |
9.36 | |||
startTransaction | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
4.13 | |||
rollbackTransaction | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
4.13 | |||
commitTransaction | |
80.00% |
4 / 5 |
|
0.00% |
0 / 1 |
4.13 | |||
inTransaction | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
getInsertID | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
getErrorMsg | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getErrorNo | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__createTemporaryTable | |
49.29% |
69 / 140 |
|
0.00% |
0 / 1 |
260.26 | |||
__dropTemporaryTable | |
61.11% |
11 / 18 |
|
0.00% |
0 / 1 |
13.76 | |||
__createView | |
50.83% |
61 / 120 |
|
0.00% |
0 / 1 |
240.79 | |||
createTemporaryTable | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
dropTemporaryTable | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
getDateExtract | |
36.36% |
4 / 11 |
|
0.00% |
0 / 1 |
15.28 | |||
getCurrentDatetime | |
44.44% |
4 / 9 |
|
0.00% |
0 / 1 |
6.74 | |||
getCurrentTimestamp | |
44.44% |
4 / 9 |
|
0.00% |
0 / 1 |
6.74 | |||
castToText | |
60.00% |
3 / 5 |
|
0.00% |
0 / 1 |
2.26 | |||
createDump | |
100.00% |
17 / 17 |
|
100.00% |
1 / 1 |
7 |
1 | <?php |
2 | /** |
3 | * Implementation of database access using PDO |
4 | * |
5 | * @category DMS |
6 | * @package SeedDMS_Core |
7 | * @license GPL 2 |
8 | * @version @version@ |
9 | * @author Uwe Steinmann <uwe@steinmann.cx> |
10 | * @copyright Copyright (C) 2012 Uwe Steinmann |
11 | * @version Release: @package_version@ |
12 | */ |
13 | /** @noinspection PhpUndefinedClassInspection */ |
14 | |
15 | /** |
16 | * Class to represent the database access for the document management |
17 | * This class uses PDO for the actual database access. |
18 | * |
19 | * @category DMS |
20 | * @package SeedDMS_Core |
21 | * @author Uwe Steinmann <uwe@steinmann.cx> |
22 | * @copyright Copyright (C) 2012 Uwe Steinmann |
23 | * @version Release: @package_version@ |
24 | */ |
25 | class SeedDMS_Core_DatabaseAccess { |
26 | /** |
27 | * @var boolean set to true for debug mode |
28 | */ |
29 | public $_debug; |
30 | |
31 | /** |
32 | * @var string name of database driver (mysql or sqlite) |
33 | */ |
34 | protected $_driver; |
35 | |
36 | /** |
37 | * @var string name of hostname |
38 | */ |
39 | protected $_hostname; |
40 | |
41 | /** |
42 | * @var int port number of database |
43 | */ |
44 | protected $_port; |
45 | |
46 | /** |
47 | * @var string name of database |
48 | */ |
49 | protected $_database; |
50 | |
51 | /** |
52 | * @var string name of database user |
53 | */ |
54 | protected $_user; |
55 | |
56 | /** |
57 | * @var string password of database user |
58 | */ |
59 | protected $_passw; |
60 | |
61 | /** |
62 | * @var object internal database connection |
63 | */ |
64 | private $_conn; |
65 | |
66 | /** |
67 | * @var boolean set to true if connection to database is established |
68 | */ |
69 | private $_connected; |
70 | |
71 | /** |
72 | * @var boolean set to true if temp. table for tree view has been created |
73 | */ |
74 | private $_ttreviewid; |
75 | |
76 | /** |
77 | * @var boolean set to true if temp. table for approvals has been created |
78 | */ |
79 | private $_ttapproveid; |
80 | |
81 | /** |
82 | * @var boolean set to true if temp. table for doc status has been created |
83 | */ |
84 | private $_ttstatid; |
85 | |
86 | /** |
87 | * @var boolean set to true if temp. table for doc content has been created |
88 | */ |
89 | private $_ttcontentid; |
90 | |
91 | /** |
92 | * @var boolean set to true if in a database transaction |
93 | */ |
94 | private $_intransaction; |
95 | |
96 | /** |
97 | * @var string set a valid file name for logging all sql queries |
98 | */ |
99 | private $_logfile; |
100 | |
101 | /** |
102 | * @var resource file pointer of log file |
103 | */ |
104 | private $_logfp; |
105 | |
106 | /** |
107 | * @var boolean set to true if views instead of temp. tables shall be used |
108 | */ |
109 | private $_useviews; |
110 | |
111 | /** |
112 | * Return list of all database tables |
113 | * |
114 | * This function is used to retrieve a list of database tables for backup |
115 | * |
116 | * @return string[]|bool list of table names |
117 | */ |
118 | function TableList() { /* {{{ */ |
119 | switch($this->_driver) { |
120 | case 'mysql': |
121 | $sql = "SELECT `TABLE_NAME` AS `name` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA`='".$this->_database."' AND `TABLE_TYPE`='BASE TABLE'"; |
122 | break; |
123 | case 'sqlite': |
124 | $sql = "SELECT tbl_name AS name FROM sqlite_master WHERE type='table'"; |
125 | break; |
126 | case 'pgsql': |
127 | $sql = "select tablename as name from pg_catalog.pg_tables where schemaname='public'"; |
128 | break; |
129 | default: |
130 | return false; |
131 | } |
132 | $arr = $this->getResultArray($sql); |
133 | $res = array(); |
134 | foreach($arr as $tmp) |
135 | $res[] = $tmp['name']; |
136 | return $res; |
137 | } /* }}} */ |
138 | |
139 | /** |
140 | * Check if database has a table |
141 | * |
142 | * This function will check if the database has a table with the given table name |
143 | * |
144 | * @return bool true if table exists, otherwise false |
145 | */ |
146 | function hasTable($name) { /* {{{ */ |
147 | switch($this->_driver) { |
148 | case 'mysql': |
149 | $sql = "SELECT `TABLE_NAME` AS `name` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA`='".$this->_database."' AND `TABLE_TYPE`='BASE TABLE' AND `TABLE_NAME`=".$this->qstr($name); |
150 | break; |
151 | case 'sqlite': |
152 | $sql = "SELECT tbl_name AS name FROM sqlite_master WHERE type='table' AND `tbl_name`=".$this->qstr($name); |
153 | break; |
154 | case 'pgsql': |
155 | $sql = "SELECT tablename AS name FROM pg_catalog.pg_tables WHERE schemaname='public' AND tablename=".$this->qstr($name); |
156 | break; |
157 | default: |
158 | return false; |
159 | } |
160 | $arr = $this->getResultArray($sql); |
161 | if($arr) |
162 | return true; |
163 | return false; |
164 | } /* }}} */ |
165 | |
166 | /** |
167 | * Return list of all database views |
168 | * |
169 | * This function is used to retrieve a list of database views |
170 | * |
171 | * @return array list of view names |
172 | */ |
173 | public function ViewList() { /* {{{ */ |
174 | switch($this->_driver) { |
175 | case 'mysql': |
176 | $sql = "select TABLE_NAME as name from information_schema.views where TABLE_SCHEMA='".$this->_database."'"; |
177 | break; |
178 | case 'sqlite': |
179 | $sql = "select tbl_name as name from sqlite_master where type='view'"; |
180 | break; |
181 | case 'pgsql': |
182 | $sql = "select viewname as name from pg_catalog.pg_views where schemaname='public'"; |
183 | break; |
184 | default: |
185 | return false; |
186 | } |
187 | $arr = $this->getResultArray($sql); |
188 | $res = array(); |
189 | foreach($arr as $tmp) |
190 | $res[] = $tmp['name']; |
191 | return $res; |
192 | } /* }}} */ |
193 | |
194 | /** |
195 | * Constructor of SeedDMS_Core_DatabaseAccess |
196 | * |
197 | * Sets all database parameters but does not connect. |
198 | * |
199 | * @param string $driver the database type e.g. mysql, sqlite |
200 | * @param string $hostname host of database server |
201 | * @param string $user name of user having access to database |
202 | * @param string $passw password of user |
203 | * @param bool|string $database name of database |
204 | */ |
205 | function __construct($driver, $hostname, $user, $passw, $database = false) { /* {{{ */ |
206 | $this->_driver = $driver; |
207 | $tmp = explode(":", $hostname); |
208 | $this->_hostname = $tmp[0]; |
209 | $this->_port = null; |
210 | if(!empty($tmp[1])) |
211 | $this->_port = $tmp[1]; |
212 | $this->_database = $database; |
213 | $this->_user = $user; |
214 | $this->_passw = $passw; |
215 | $this->_connected = false; |
216 | $this->_intransaction = 0; |
217 | $this->_logfile = ''; |
218 | if($this->_logfile) { |
219 | $this->_logfp = fopen($this->_logfile, 'a+'); |
220 | if($this->_logfp) |
221 | fwrite($this->_logfp, microtime(true)." BEGIN ".$_SERVER['REQUEST_URI']." ------------------------------------------\n"); |
222 | } else |
223 | $this->_logfp = null; |
224 | // $tt*****id is a hack to ensure that we do not try to create the |
225 | // temporary table twice during a single connection. Can be fixed by |
226 | // using Views (MySQL 5.0 onward) instead of temporary tables. |
227 | // CREATE ... IF NOT EXISTS cannot be used because it has the |
228 | // unpleasant side-effect of performing the insert again even if the |
229 | // table already exists. |
230 | // |
231 | // See createTemporaryTable() method for implementation. |
232 | $this->_ttreviewid = false; |
233 | $this->_ttapproveid = false; |
234 | $this->_ttstatid = false; |
235 | $this->_ttcontentid = false; |
236 | $this->_useviews = false; // turn off views, because they are much slower then temp. tables. They also break the transaction management, because dropping a view will commit the current transaction. |
237 | $this->_debug = false; |
238 | } /* }}} */ |
239 | |
240 | /** |
241 | * Return driver |
242 | * |
243 | * @return string name of driver as set in constructor |
244 | */ |
245 | public function getDriver() { /* {{{ */ |
246 | return $this->_driver; |
247 | } /* }}} */ |
248 | |
249 | /** |
250 | * Turn on views instead of temp. tables |
251 | * |
252 | * @param bool $onoff turn use of views instead of temp. table on/off |
253 | */ |
254 | function useViews($onoff) { /* {{{ */ |
255 | $this->_useviews = $onoff; |
256 | } /* }}} */ |
257 | |
258 | /** |
259 | * Destructor of SeedDMS_Core_DatabaseAccess |
260 | */ |
261 | function __destruct() { /* {{{ */ |
262 | if($this->_logfile && $this->_logfp) { |
263 | fwrite($this->_logfp, microtime(true)." END --------------------------------------------\n"); |
264 | fclose($this->_logfp); |
265 | } |
266 | } /* }}} */ |
267 | |
268 | /** |
269 | * Set the file pointer to a log file |
270 | * |
271 | * Once it is set, all queries will be logged into this file |
272 | */ |
273 | function setLogFp($fp) { /* {{{ */ |
274 | $this->_logfp = $fp; |
275 | } /* }}} */ |
276 | |
277 | /** |
278 | * Connect to database |
279 | * |
280 | * @return boolean true if connection could be established, otherwise false |
281 | */ |
282 | function connect() { /* {{{ */ |
283 | switch($this->_driver) { |
284 | case 'mysql': |
285 | case 'mysqli': |
286 | case 'mysqlnd': |
287 | case 'pgsql': |
288 | $dsn = $this->_driver.":dbname=".$this->_database.";host=".$this->_hostname; |
289 | if($this->_port) |
290 | $dsn .= ";port=".$this->_port; |
291 | break; |
292 | case 'sqlite': |
293 | $dsn = $this->_driver.":".$this->_database; |
294 | break; |
295 | } |
296 | try { |
297 | /** @noinspection PhpUndefinedVariableInspection */ |
298 | $this->_conn = new PDO($dsn, $this->_user, $this->_passw); |
299 | if (!$this->_conn) |
300 | return false; |
301 | /* Prevent PDO from throwing an exception because the code currently |
302 | * cannot handle it. PDO::ERRMODE_EXCEPTION became the default as of php 8.0.0 |
303 | * PDO::ERRMODE_SILENT was the default before php 8.0.0 |
304 | */ |
305 | $this->_conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_SILENT); |
306 | |
307 | switch($this->_driver) { |
308 | case 'mysql': |
309 | $this->_conn->exec('SET NAMES utf8'); |
310 | // $this->_conn->setAttribute(PDO::ATTR_AUTOCOMMIT, FALSE); |
311 | /* Turn this on if you want strict checking of default values, etc. */ |
312 | /* $this->_conn->exec("SET SESSION sql_mode = 'STRICT_TRANS_TABLES'"); */ |
313 | /* The following is the default on Ubuntu 16.04 */ |
314 | /* $this->_conn->exec("SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'"); */ |
315 | break; |
316 | case 'sqlite': |
317 | $this->_conn->exec('PRAGMA foreign_keys = ON'); |
318 | break; |
319 | } |
320 | } catch (Exception $e) { |
321 | return false; |
322 | } |
323 | if($this->_useviews) { |
324 | $tmp = $this->ViewList(); |
325 | foreach(array('ttreviewid', 'ttapproveid', 'ttstatid', 'ttcontentid') as $viewname) { |
326 | if(in_array($viewname, $tmp)) { |
327 | $this->{"_".$viewname} = true; |
328 | } |
329 | } |
330 | } |
331 | |
332 | $this->_connected = true; |
333 | return true; |
334 | } /* }}} */ |
335 | |
336 | /** |
337 | * Make sure a database connection exisits |
338 | * |
339 | * This function checks for a database connection. If it does not exists |
340 | * it will reconnect. |
341 | * |
342 | * @return boolean true if connection is established, otherwise false |
343 | */ |
344 | function ensureConnected() { /* {{{ */ |
345 | if (!$this->_connected) return $this->connect(); |
346 | else return true; |
347 | } /* }}} */ |
348 | |
349 | /** |
350 | * Sanitize String used in database operations |
351 | * |
352 | * @param string $text |
353 | * @return string sanitized string |
354 | */ |
355 | function qstr($text) { /* {{{ */ |
356 | return $this->_conn->quote($text); |
357 | } /* }}} */ |
358 | |
359 | /** |
360 | * Replace back ticks by '"' |
361 | * |
362 | * @param string $text |
363 | * @return string sanitized string |
364 | */ |
365 | function rbt($text) { /* {{{ */ |
366 | return str_replace('`', '"', $text); |
367 | } /* }}} */ |
368 | |
369 | /** |
370 | * Return sql to concat strings or fields |
371 | * |
372 | * @param array $arr list of field names or strings |
373 | * @return string concated string |
374 | */ |
375 | function concat($arr) { /* {{{ */ |
376 | switch($this->_driver) { |
377 | case 'mysql': |
378 | return 'concat('.implode(',', $arr).')'; |
379 | break; |
380 | case 'pgsql': |
381 | return implode(' || ', $arr); |
382 | break; |
383 | case 'sqlite': |
384 | return implode(' || ', $arr); |
385 | break; |
386 | } |
387 | return ''; |
388 | } /* }}} */ |
389 | |
390 | /** |
391 | * Execute SQL query and return result |
392 | * |
393 | * Call this function only with sql query which return data records. |
394 | * |
395 | * @param string $queryStr sql query |
396 | * @param bool $retick |
397 | * @return array|bool data if query could be executed otherwise false |
398 | */ |
399 | function getResultArray($queryStr, $retick=true) { /* {{{ */ |
400 | $resArr = array(); |
401 | |
402 | if($retick && $this->_driver == 'pgsql') { |
403 | $queryStr = $this->rbt($queryStr); |
404 | } |
405 | |
406 | if($this->_logfp) { |
407 | fwrite($this->_logfp, microtime(true)." ".($this->_conn->inTransaction() ? '*' : ' ')." ".$queryStr."\n"); |
408 | } |
409 | $res = $this->_conn->query($queryStr); |
410 | if ($res === false) { |
411 | if($this->_debug) { |
412 | echo "error: ".$queryStr."<br />"; |
413 | print_r($this->_conn->errorInfo()); |
414 | } |
415 | return false; |
416 | } |
417 | $resArr = $res->fetchAll(PDO::FETCH_ASSOC); |
418 | // $res->Close(); |
419 | return $resArr; |
420 | } /* }}} */ |
421 | |
422 | /** |
423 | * Execute SQL query |
424 | * |
425 | * Call this function only with sql query which do not return data records. |
426 | * |
427 | * @param string $queryStr sql query |
428 | * @param boolean $retick replace all '`' by '"' |
429 | * @return boolean true if query could be executed otherwise false |
430 | */ |
431 | function getResult($queryStr, $retick=true) { /* {{{ */ |
432 | if($retick && $this->_driver == 'pgsql') { |
433 | $queryStr = $this->rbt($queryStr); |
434 | } |
435 | |
436 | if($this->_logfp) { |
437 | fwrite($this->_logfp, microtime(true)." ".($this->_conn->inTransaction() ? '*' : ' ')." ".$queryStr."\n"); |
438 | } |
439 | $res = $this->_conn->exec($queryStr); |
440 | if($res === false) { |
441 | if($this->_debug) { |
442 | echo "error: ".$queryStr."<br />"; |
443 | print_r($this->_conn->errorInfo()); |
444 | } |
445 | return false; |
446 | } else |
447 | return true; |
448 | |
449 | return $res; |
450 | } /* }}} */ |
451 | |
452 | function startTransaction() { /* {{{ */ |
453 | if(!$this->_intransaction) { |
454 | $this->_conn->beginTransaction(); |
455 | } |
456 | $this->_intransaction++; |
457 | if($this->_logfp) { |
458 | fwrite($this->_logfp, microtime(true)." ".($this->_conn->inTransaction() ? '*' : ' ')." START ".$this->_intransaction."\n"); |
459 | } |
460 | } /* }}} */ |
461 | |
462 | function rollbackTransaction() { /* {{{ */ |
463 | if($this->_logfp) { |
464 | fwrite($this->_logfp, microtime(true)." ".($this->_conn->inTransaction() ? '*' : ' ')." ROLLBACK ".$this->_intransaction."\n"); |
465 | } |
466 | if($this->_intransaction == 1) { |
467 | $this->_conn->rollBack(); |
468 | } |
469 | $this->_intransaction--; |
470 | } /* }}} */ |
471 | |
472 | function commitTransaction() { /* {{{ */ |
473 | if($this->_logfp) { |
474 | fwrite($this->_logfp, microtime(true)." ".($this->_conn->inTransaction() ? '*' : ' ')." COMMIT ".$this->_intransaction."\n"); |
475 | } |
476 | if($this->_intransaction == 1) { |
477 | $this->_conn->commit(); |
478 | } |
479 | $this->_intransaction--; |
480 | } /* }}} */ |
481 | |
482 | function inTransaction() { /* {{{ */ |
483 | return $this->_conn->inTransaction(); |
484 | } /* }}} */ |
485 | |
486 | /** |
487 | * Return the id of the last instert record |
488 | * |
489 | * @param string $tablename |
490 | * @param string $fieldname |
491 | * @return int id used in last autoincrement |
492 | */ |
493 | function getInsertID($tablename='', $fieldname='id') { /* {{{ */ |
494 | if($this->_driver == 'pgsql') |
495 | return $this->_conn->lastInsertId('"'.$tablename.'_'.$fieldname.'_seq"'); |
496 | else |
497 | return $this->_conn->lastInsertId(); |
498 | } /* }}} */ |
499 | |
500 | function getErrorMsg() { /* {{{ */ |
501 | $info = $this->_conn->errorInfo(); |
502 | return($info[2]); |
503 | } /* }}} */ |
504 | |
505 | function getErrorNo() { /* {{{ */ |
506 | return $this->_conn->errorCode(); |
507 | } /* }}} */ |
508 | |
509 | /** |
510 | * Create various temporary tables to speed up and simplify sql queries |
511 | * |
512 | * @param string $tableName |
513 | * @param bool $override |
514 | * @return bool |
515 | */ |
516 | private function __createTemporaryTable($tableName, $override=false) { /* {{{ */ |
517 | if (!strcasecmp($tableName, "ttreviewid")) { |
518 | switch($this->_driver) { |
519 | case 'sqlite': |
520 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` AS ". |
521 | "SELECT `tblDocumentReviewLog`.`reviewID` AS `reviewID`, ". |
522 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
523 | "FROM `tblDocumentReviewLog` ". |
524 | "GROUP BY `tblDocumentReviewLog`.`reviewID` "; //. |
525 | // "ORDER BY `maxLogID`"; |
526 | $dropStr = "DROP TABLE IF EXISTS `ttreviewid`"; |
527 | break; |
528 | case 'pgsql': |
529 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` (`reviewID` INTEGER, `maxLogID` INTEGER, PRIMARY KEY (`reviewID`));". |
530 | "INSERT INTO `ttreviewid` SELECT `tblDocumentReviewLog`.`reviewID`, ". |
531 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
532 | "FROM `tblDocumentReviewLog` ". |
533 | "GROUP BY `tblDocumentReviewLog`.`reviewID` ";//. |
534 | // "ORDER BY `maxLogID`"; |
535 | $dropStr = "DROP TABLE IF EXISTS `ttreviewid`"; |
536 | break; |
537 | default: |
538 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttreviewid` (PRIMARY KEY (`reviewID`), INDEX (`maxLogID`)) ". |
539 | "SELECT `tblDocumentReviewLog`.`reviewID`, ". |
540 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
541 | "FROM `tblDocumentReviewLog` ". |
542 | "GROUP BY `tblDocumentReviewLog`.`reviewID` "; //. |
543 | // "ORDER BY `maxLogID`"; |
544 | $dropStr = "DROP TEMPORARY TABLE IF EXISTS `ttreviewid`"; |
545 | } |
546 | if (!$this->_ttreviewid) { |
547 | if (!$this->getResult($queryStr)) |
548 | return false; |
549 | $this->_ttreviewid=true; |
550 | } |
551 | else { |
552 | if (is_bool($override) && $override) { |
553 | if (!$this->getResult($dropStr)) |
554 | return false; |
555 | if (!$this->getResult($queryStr)) |
556 | return false; |
557 | } |
558 | } |
559 | return $this->_ttreviewid; |
560 | } |
561 | elseif (!strcasecmp($tableName, "ttapproveid")) { |
562 | switch($this->_driver) { |
563 | case 'sqlite': |
564 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` AS ". |
565 | "SELECT `tblDocumentApproveLog`.`approveID` AS `approveID`, ". |
566 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
567 | "FROM `tblDocumentApproveLog` ". |
568 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; //. |
569 | // "ORDER BY `maxLogID`"; |
570 | $dropStr = "DROP TABLE IF EXISTS `ttapproveid`"; |
571 | break; |
572 | case 'pgsql': |
573 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` (`approveID` INTEGER, `maxLogID` INTEGER, PRIMARY KEY (`approveID`));". |
574 | "INSERT INTO `ttapproveid` SELECT `tblDocumentApproveLog`.`approveID`, ". |
575 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
576 | "FROM `tblDocumentApproveLog` ". |
577 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; //. |
578 | // "ORDER BY `maxLogID`"; |
579 | $dropStr = "DROP TABLE IF EXISTS `ttapproveid`"; |
580 | break; |
581 | default: |
582 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttapproveid` (PRIMARY KEY (`approveID`), INDEX (`maxLogID`)) ". |
583 | "SELECT `tblDocumentApproveLog`.`approveID`, ". |
584 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
585 | "FROM `tblDocumentApproveLog` ". |
586 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; //. |
587 | // "ORDER BY `maxLogID`"; |
588 | $dropStr = "DROP TEMPORARY TABLE IF EXISTS `ttapproveid`"; |
589 | } |
590 | if (!$this->_ttapproveid) { |
591 | if (!$this->getResult($queryStr)) |
592 | return false; |
593 | $this->_ttapproveid=true; |
594 | } |
595 | else { |
596 | if (is_bool($override) && $override) { |
597 | if (!$this->getResult($dropStr)) |
598 | return false; |
599 | if (!$this->getResult($queryStr)) |
600 | return false; |
601 | } |
602 | } |
603 | return $this->_ttapproveid; |
604 | } |
605 | elseif (!strcasecmp($tableName, "ttstatid")) { |
606 | switch($this->_driver) { |
607 | case 'sqlite': |
608 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` AS ". |
609 | "SELECT `tblDocumentStatusLog`.`statusID` AS `statusID`, ". |
610 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
611 | "FROM `tblDocumentStatusLog` ". |
612 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; //. |
613 | // "ORDER BY `maxLogID`"; |
614 | $dropStr = "DROP TABLE IF EXISTS `ttstatid`"; |
615 | break; |
616 | case 'pgsql': |
617 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` (`statusID` INTEGER, `maxLogID` INTEGER, PRIMARY KEY (`statusID`));". |
618 | "INSERT INTO `ttstatid` SELECT `tblDocumentStatusLog`.`statusID`, ". |
619 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
620 | "FROM `tblDocumentStatusLog` ". |
621 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; //. |
622 | // "ORDER BY `maxLogID`"; |
623 | $dropStr = "DROP TABLE IF EXISTS `ttstatid`"; |
624 | break; |
625 | default: |
626 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttstatid` (PRIMARY KEY (`statusID`), INDEX (`maxLogID`)) ". |
627 | "SELECT `tblDocumentStatusLog`.`statusID`, ". |
628 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
629 | "FROM `tblDocumentStatusLog` ". |
630 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; //. |
631 | // "ORDER BY `maxLogID`"; |
632 | $dropStr = "DROP TEMPORARY TABLE IF EXISTS `ttstatid`"; |
633 | } |
634 | if (!$this->_ttstatid) { |
635 | if (!$this->getResult($queryStr)) |
636 | return false; |
637 | $this->_ttstatid=true; |
638 | } |
639 | else { |
640 | if (is_bool($override) && $override) { |
641 | if (!$this->getResult($dropStr)) |
642 | return false; |
643 | if (!$this->getResult($queryStr)) |
644 | return false; |
645 | } |
646 | } |
647 | return $this->_ttstatid; |
648 | } |
649 | elseif (!strcasecmp($tableName, "ttcontentid")) { |
650 | switch($this->_driver) { |
651 | case 'sqlite': |
652 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttcontentid` AS ". |
653 | "SELECT `tblDocumentContent`.`document` AS `document`, ". |
654 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
655 | "FROM `tblDocumentContent` ". |
656 | "GROUP BY `tblDocumentContent`.`document` ". |
657 | "ORDER BY `tblDocumentContent`.`document`"; |
658 | $dropStr = "DROP TABLE IF EXISTS `ttcontentid`"; |
659 | break; |
660 | case 'pgsql': |
661 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttcontentid` (`document` INTEGER, `maxVersion` INTEGER, PRIMARY KEY (`document`)); ". |
662 | "INSERT INTO `ttcontentid` SELECT `tblDocumentContent`.`document` AS `document`, ". |
663 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
664 | "FROM `tblDocumentContent` ". |
665 | "GROUP BY `tblDocumentContent`.`document` ". |
666 | "ORDER BY `tblDocumentContent`.`document`"; |
667 | $dropStr = "DROP TABLE IF EXISTS `ttcontentid`"; |
668 | break; |
669 | default: |
670 | $queryStr = "CREATE TEMPORARY TABLE IF NOT EXISTS `ttcontentid` (PRIMARY KEY (`document`), INDEX (`maxVersion`)) ". |
671 | "SELECT `tblDocumentContent`.`document`, ". |
672 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
673 | "FROM `tblDocumentContent` ". |
674 | "GROUP BY `tblDocumentContent`.`document` ". |
675 | "ORDER BY `tblDocumentContent`.`document`"; |
676 | $dropStr = "DROP TEMPORARY TABLE IF EXISTS `ttcontentid`"; |
677 | } |
678 | if (!$this->_ttcontentid) { |
679 | if (!$this->getResult($queryStr)) |
680 | return false; |
681 | $this->_ttcontentid=true; |
682 | } |
683 | else { |
684 | if (is_bool($override) && $override) { |
685 | if (!$this->getResult($dropStr)) |
686 | return false; |
687 | if (!$this->getResult($queryStr)) |
688 | return false; |
689 | } |
690 | } |
691 | return $this->_ttcontentid; |
692 | } |
693 | return false; |
694 | } /* }}} */ |
695 | |
696 | /** |
697 | * Drop various temporary tables to enforce recreation when needed |
698 | * |
699 | * @param string $tableName |
700 | * |
701 | * @return bool |
702 | */ |
703 | private function __dropTemporaryTable($tableName) { /* {{{ */ |
704 | $queryStr = ''; |
705 | if($this->_driver == 'sqlite' || $this->_driver == 'pgsql') |
706 | $t = ''; |
707 | else |
708 | $t = 'TEMPORARY'; |
709 | if (!strcasecmp($tableName, "ttreviewid")) { |
710 | $queryStr = "DROP ".$t." TABLE IF EXISTS `ttreviewid`"; |
711 | } elseif (!strcasecmp($tableName, "ttapproveid")) { |
712 | $queryStr = "DROP ".$t." TABLE IF EXISTS `ttapproveid`"; |
713 | } elseif (!strcasecmp($tableName, "ttstatid")) { |
714 | $queryStr = "DROP ".$t." TABLE IF EXISTS `ttstatid`"; |
715 | } elseif (!strcasecmp($tableName, "ttcontentid")) { |
716 | $queryStr = "DROP ".$t." TABLE IF EXISTS `ttcontentid`"; |
717 | } |
718 | if($queryStr) { |
719 | if (!$this->getResult($queryStr)) |
720 | return false; |
721 | else { |
722 | $this->{'_'.$tableName} = false; |
723 | return true; |
724 | } |
725 | } |
726 | return false; |
727 | } /* }}} */ |
728 | |
729 | /** |
730 | * Create various views to speed up and simplify sql queries |
731 | * |
732 | * @param string $tableName |
733 | * @param bool $override |
734 | * |
735 | * @return bool |
736 | */ |
737 | private function __createView($tableName, $override=false) { /* {{{ */ |
738 | if (!strcasecmp($tableName, "ttreviewid")) { |
739 | switch($this->_driver) { |
740 | case 'sqlite': |
741 | $queryStr = "CREATE VIEW IF NOT EXISTS `ttreviewid` AS ". |
742 | "SELECT `tblDocumentReviewLog`.`reviewID` AS `reviewID`, ". |
743 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
744 | "FROM `tblDocumentReviewLog` ". |
745 | "GROUP BY `tblDocumentReviewLog`.`reviewID` "; //. |
746 | break; |
747 | case 'pgsql': |
748 | $queryStr = "CREATE VIEW `ttreviewid` AS ". |
749 | "SELECT `tblDocumentReviewLog`.`reviewID` AS `reviewID`, ". |
750 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
751 | "FROM `tblDocumentReviewLog` ". |
752 | "GROUP BY `tblDocumentReviewLog`.`reviewID` "; |
753 | break; |
754 | default: |
755 | $queryStr = "CREATE".($override ? " OR REPLACE" : "")." VIEW `ttreviewid` AS ". |
756 | "SELECT `tblDocumentReviewLog`.`reviewID` AS `reviewID`, ". |
757 | "MAX(`tblDocumentReviewLog`.`reviewLogID`) AS `maxLogID` ". |
758 | "FROM `tblDocumentReviewLog` ". |
759 | "GROUP BY `tblDocumentReviewLog`.`reviewID` "; |
760 | } |
761 | if (!$this->_ttreviewid) { |
762 | if (!$this->getResult($queryStr)) |
763 | return false; |
764 | $this->_ttreviewid=true; |
765 | } |
766 | else { |
767 | if (is_bool($override) && $override) { |
768 | // if (!$this->getResult("DROP VIEW `ttreviewid`")) |
769 | // return false; |
770 | if (!$this->getResult($queryStr)) |
771 | return false; |
772 | } |
773 | } |
774 | return $this->_ttreviewid; |
775 | } |
776 | elseif (!strcasecmp($tableName, "ttapproveid")) { |
777 | switch($this->_driver) { |
778 | case 'sqlite': |
779 | $queryStr = "CREATE VIEW IF NOT EXISTS `ttapproveid` AS ". |
780 | "SELECT `tblDocumentApproveLog`.`approveID` AS `approveID`, ". |
781 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
782 | "FROM `tblDocumentApproveLog` ". |
783 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; //. |
784 | break; |
785 | case 'pgsql': |
786 | $queryStr = "CREATE VIEW `ttapproveid` AS ". |
787 | "SELECT `tblDocumentApproveLog`.`approveID` AS `approveID`, ". |
788 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
789 | "FROM `tblDocumentApproveLog` ". |
790 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; |
791 | break; |
792 | default: |
793 | $queryStr = "CREATE".($override ? " OR REPLACE" : "")." VIEW `ttapproveid` AS ". |
794 | "SELECT `tblDocumentApproveLog`.`approveID`, ". |
795 | "MAX(`tblDocumentApproveLog`.`approveLogID`) AS `maxLogID` ". |
796 | "FROM `tblDocumentApproveLog` ". |
797 | "GROUP BY `tblDocumentApproveLog`.`approveID` "; |
798 | } |
799 | if (!$this->_ttapproveid) { |
800 | if (!$this->getResult($queryStr)) |
801 | return false; |
802 | $this->_ttapproveid=true; |
803 | } |
804 | else { |
805 | if (is_bool($override) && $override) { |
806 | // if (!$this->getResult("DROP VIEW `ttapproveid`")) |
807 | // return false; |
808 | if (!$this->getResult($queryStr)) |
809 | return false; |
810 | } |
811 | } |
812 | return $this->_ttapproveid; |
813 | } |
814 | elseif (!strcasecmp($tableName, "ttstatid")) { |
815 | switch($this->_driver) { |
816 | case 'sqlite': |
817 | $queryStr = "CREATE VIEW IF NOT EXISTS `ttstatid` AS ". |
818 | "SELECT `tblDocumentStatusLog`.`statusID` AS `statusID`, ". |
819 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
820 | "FROM `tblDocumentStatusLog` ". |
821 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; |
822 | break; |
823 | case 'pgsql': |
824 | $queryStr = "CREATE VIEW `ttstatid` AS ". |
825 | "SELECT `tblDocumentStatusLog`.`statusID` AS `statusID`, ". |
826 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
827 | "FROM `tblDocumentStatusLog` ". |
828 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; |
829 | break; |
830 | default: |
831 | $queryStr = "CREATE".($override ? " OR REPLACE" : "")." VIEW `ttstatid` AS ". |
832 | "SELECT `tblDocumentStatusLog`.`statusID`, ". |
833 | "MAX(`tblDocumentStatusLog`.`statusLogID`) AS `maxLogID` ". |
834 | "FROM `tblDocumentStatusLog` ". |
835 | "GROUP BY `tblDocumentStatusLog`.`statusID` "; |
836 | } |
837 | if (!$this->_ttstatid) { |
838 | if (!$this->getResult($queryStr)) |
839 | return false; |
840 | $this->_ttstatid=true; |
841 | } |
842 | else { |
843 | if (is_bool($override) && $override) { |
844 | // if (!$this->getResult("DROP VIEW `ttstatid`")) |
845 | // return false; |
846 | if (!$this->getResult($queryStr)) |
847 | return false; |
848 | } |
849 | } |
850 | return $this->_ttstatid; |
851 | } |
852 | elseif (!strcasecmp($tableName, "ttcontentid")) { |
853 | switch($this->_driver) { |
854 | case 'sqlite': |
855 | $queryStr = "CREATE VIEW IF NOT EXISTS `ttcontentid` AS ". |
856 | "SELECT `tblDocumentContent`.`document` AS `document`, ". |
857 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
858 | "FROM `tblDocumentContent` ". |
859 | "GROUP BY `tblDocumentContent`.`document` ". |
860 | "ORDER BY `tblDocumentContent`.`document`"; |
861 | break; |
862 | case 'pgsql': |
863 | $queryStr = "CREATE VIEW `ttcontentid` AS ". |
864 | "SELECT `tblDocumentContent`.`document` AS `document`, ". |
865 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
866 | "FROM `tblDocumentContent` ". |
867 | "GROUP BY `tblDocumentContent`.`document` ". |
868 | "ORDER BY `tblDocumentContent`.`document`"; |
869 | break; |
870 | default: |
871 | $queryStr = "CREATE".($override ? " OR REPLACE" : "")." VIEW `ttcontentid` AS ". |
872 | "SELECT `tblDocumentContent`.`document`, ". |
873 | "MAX(`tblDocumentContent`.`version`) AS `maxVersion` ". |
874 | "FROM `tblDocumentContent` ". |
875 | "GROUP BY `tblDocumentContent`.`document` ". |
876 | "ORDER BY `tblDocumentContent`.`document`"; |
877 | } |
878 | if (!$this->_ttcontentid) { |
879 | if (!$this->getResult($queryStr)) |
880 | return false; |
881 | $this->_ttcontentid=true; |
882 | } |
883 | else { |
884 | if (is_bool($override) && $override) { |
885 | // if (!$this->getResult("DROP VIEW `ttcontentid`")) |
886 | // return false; |
887 | if (!$this->getResult($queryStr)) |
888 | return false; |
889 | } |
890 | } |
891 | return $this->_ttcontentid; |
892 | } |
893 | return false; |
894 | } /* }}} */ |
895 | |
896 | /** |
897 | * Create various temporary tables or view to speed up and simplify sql queries |
898 | * |
899 | * @param string $tableName |
900 | * @param bool $override |
901 | * |
902 | * @return bool |
903 | */ |
904 | public function createTemporaryTable($tableName, $override=false) { /* {{{ */ |
905 | if($this->_useviews) |
906 | return $this->__createView($tableName, $override); |
907 | else |
908 | return $this->__createTemporaryTable($tableName, $override); |
909 | } /* }}} */ |
910 | |
911 | /** |
912 | * Drop various temporary tables to force recreation when next time needed |
913 | * |
914 | * @param string $tableName |
915 | * |
916 | * @return bool |
917 | */ |
918 | public function dropTemporaryTable($tableName) { /* {{{ */ |
919 | if($this->_useviews) |
920 | return true; // No need to recreate a view |
921 | else |
922 | return $this->__dropTemporaryTable($tableName); |
923 | } /* }}} */ |
924 | |
925 | /** |
926 | * Return sql statement for extracting the date part from a field |
927 | * containing a unix timestamp |
928 | * |
929 | * @param string $fieldname name of field containing the timestamp |
930 | * @param string $format |
931 | * @return string sql code |
932 | */ |
933 | function getDateExtract($fieldname, $format='%Y-%m-%d') { /* {{{ */ |
934 | switch($this->_driver) { |
935 | case 'mysql': |
936 | return "from_unixtime(`".$fieldname."`, ".$this->qstr($format).")"; |
937 | break; |
938 | case 'sqlite': |
939 | return "strftime(".$this->qstr($format).", `".$fieldname."`, 'unixepoch')"; |
940 | break; |
941 | case 'pgsql': |
942 | switch($format) { |
943 | case '%Y-%m': |
944 | return "to_char(to_timestamp(`".$fieldname."`), 'YYYY-MM')"; |
945 | break; |
946 | default: |
947 | return "to_char(to_timestamp(`".$fieldname."`), 'YYYY-MM-DD')"; |
948 | break; |
949 | } |
950 | break; |
951 | } |
952 | return ''; |
953 | } /* }}} */ |
954 | |
955 | /** |
956 | * Return sql statement for returning the current date and time |
957 | * in format Y-m-d H:i:s |
958 | * |
959 | * @return string sql code |
960 | */ |
961 | function getCurrentDatetime() { /* {{{ */ |
962 | switch($this->_driver) { |
963 | case 'mysql': |
964 | return "CURRENT_TIMESTAMP"; |
965 | break; |
966 | case 'sqlite': |
967 | return "datetime('now', 'localtime')"; |
968 | break; |
969 | case 'pgsql': |
970 | return "now()"; |
971 | break; |
972 | } |
973 | return ''; |
974 | } /* }}} */ |
975 | |
976 | /** |
977 | * Return sql statement for returning the current timestamp |
978 | * |
979 | * @return string sql code |
980 | */ |
981 | function getCurrentTimestamp() { /* {{{ */ |
982 | switch($this->_driver) { |
983 | case 'mysql': |
984 | return "UNIX_TIMESTAMP()"; |
985 | break; |
986 | case 'sqlite': |
987 | return "strftime('%s', 'now')"; |
988 | break; |
989 | case 'pgsql': |
990 | return "date_part('epoch',CURRENT_TIMESTAMP)::int"; |
991 | break; |
992 | } |
993 | return ''; |
994 | } /* }}} */ |
995 | |
996 | /** |
997 | * Return sql statement for returning the current timestamp |
998 | * |
999 | * @param $field |
1000 | * @return string sql code |
1001 | */ |
1002 | function castToText($field) { /* {{{ */ |
1003 | switch($this->_driver) { |
1004 | case 'pgsql': |
1005 | return $field."::TEXT"; |
1006 | break; |
1007 | } |
1008 | return $field; |
1009 | } /* }}} */ |
1010 | |
1011 | /** |
1012 | * Create an sql dump of the complete database |
1013 | * |
1014 | * @param resource $fp name of dump file |
1015 | * @return bool |
1016 | */ |
1017 | function createDump($fp) { /* {{{ */ |
1018 | $tables = $this->TableList('TABLES'); |
1019 | foreach($tables as $table) { |
1020 | if($table == 'sqlite_sequence') |
1021 | continue; |
1022 | $query = "SELECT * FROM `".$table."`"; |
1023 | $records = $this->getResultArray($query); |
1024 | fwrite($fp,"\n-- TABLE: ".$table."--\n\n"); |
1025 | foreach($records as $record) { |
1026 | $values=""; |
1027 | $i = 1; |
1028 | foreach ($record as $column) { |
1029 | if (is_numeric($column)) $values .= $column; |
1030 | else $values .= $this->qstr($column); |
1031 | |
1032 | if ($i<(count($record))) $values .= ","; |
1033 | $i++; |
1034 | } |
1035 | |
1036 | fwrite($fp, "INSERT INTO `".$table."` VALUES (".$values.");\n"); |
1037 | } |
1038 | } |
1039 | return true; |
1040 | } /* }}} */ |
1041 | } |