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