Aleksander Machniak
2013-06-08 d186405c0090772d1c26788dad9ea973f0421390
commit | author | age
0d94fd 1 <?php
AM 2
3d231c 3 /**
0d94fd 4  +-----------------------------------------------------------------------+
AM 5  | This file is part of the Roundcube Webmail client                     |
6  | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
7  |                                                                       |
8  | Licensed under the GNU General Public License version 3 or            |
9  | any later version with exceptions for skins & plugins.                |
10  | See the README file for a full license statement.                     |
11  |                                                                       |
12  | PURPOSE:                                                              |
13  |   Database wrapper class that implements PHP PDO functions            |
14  |   for MS SQL Server database                                          |
15  +-----------------------------------------------------------------------+
16  | Author: Aleksander Machniak <alec@alec.pl>                            |
17  +-----------------------------------------------------------------------+
18 */
19
20 /**
21  * Database independent query interface
22  * This is a wrapper for the PHP PDO
23  *
9ab346 24  * @package    Framework
AM 25  * @subpackage Database
0d94fd 26  */
AM 27 class rcube_db_sqlsrv extends rcube_db
28 {
88107d 29     public $db_provider = 'mssql';
TB 30
8c2375 31     /**
d18640 32      * Object constructor
AM 33      *
34      * @param string $db_dsnw DSN for read/write operations
35      * @param string $db_dsnr Optional DSN for read only operations
36      * @param bool   $pconn   Enables persistent connections
8c2375 37      */
d18640 38     public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
0d94fd 39     {
d18640 40         parent::__construct($db_dsnw, $db_dsnr, $pconn);
AM 41
0d94fd 42         $this->options['identifier_start'] = '[';
AM 43         $this->options['identifier_end'] = ']';
44     }
45
46     /**
66407a 47      * Driver-specific configuration of database connection
AM 48      *
49      * @param array $dsn DSN for DB connections
50      * @param PDO   $dbh Connection handler
51      */
52     protected function conn_configure($dsn, $dbh)
53     {
54         // Set date format in case of non-default language (#1488918)
55         $this->query("SET DATEFORMAT ymd");
56     }
57
58     /**
0d94fd 59      * Return SQL function for current time and date
AM 60      *
aa44ce 61      * @param int $interval Optional interval (in seconds) to add/subtract
AM 62      *
0d94fd 63      * @return string SQL function to use in query
AM 64      */
aa44ce 65     public function now($interval = 0)
0d94fd 66     {
aa44ce 67         if ($interval) {
AM 68             $interval = intval($interval);
69             return "dateadd(second, $interval, getdate())";
70         }
71
0d94fd 72         return "getdate()";
AM 73     }
74
75     /**
76      * Return SQL statement to convert a field value into a unix timestamp
77      *
78      * This method is deprecated and should not be used anymore due to limitations
79      * of timestamp functions in Mysql (year 2038 problem)
80      *
3d231c 81      * @param string $field Field name
0d94fd 82      *
3d231c 83      * @return string SQL statement to use in query
0d94fd 84      * @deprecated
AM 85      */
86     public function unixtimestamp($field)
87     {
88         return "DATEDIFF(second, '19700101', $field) + DATEDIFF(second, GETDATE(), GETUTCDATE())";
89     }
90
91     /**
92      * Abstract SQL statement for value concatenation
93      *
94      * @return string SQL statement to be used in query
95      */
96     public function concat(/* col1, col2, ... */)
97     {
98         $args = func_get_args();
99
100         if (is_array($args[0])) {
101             $args = $args[0];
102         }
103
104         return '(' . join('+', $args) . ')';
105     }
106
107     /**
108      * Adds TOP (LIMIT,OFFSET) clause to the query
109      *
3d231c 110      * @param string $query  SQL query
AM 111      * @param int    $limit  Number of rows
112      * @param int    $offset Offset
8c2375 113      *
AM 114      * @return string SQL query
0d94fd 115      */
AM 116     protected function set_limit($query, $limit = 0, $offset = 0)
117     {
5354c5 118         $limit  = intval($limit);
AM 119         $offset = intval($offset);
ec6a77 120         $end    = $offset + $limit;
AM 121
122         // query without OFFSET
123         if (!$offset) {
124             $query = preg_replace('/^SELECT\s/i', "SELECT TOP $limit ", $query);
125             return $query;
126         }
5354c5 127
AM 128         $orderby = stristr($query, 'ORDER BY');
ec6a77 129         $offset += 1;
AM 130
5354c5 131         if ($orderby !== false) {
ec6a77 132             $query = trim(substr($query, 0, -1 * strlen($orderby)));
AM 133         }
134         else {
135             // it shouldn't happen, paging without sorting has not much sense
136             // @FIXME: I don't know how to build paging query without ORDER BY
137             $orderby = "ORDER BY 1";
0d94fd 138         }
AM 139
ec6a77 140         $query = preg_replace('/^SELECT\s/i', '', $query);
AM 141         $query = "WITH paging AS (SELECT ROW_NUMBER() OVER ($orderby) AS [RowNumber], $query)"
142             . " SELECT * FROM paging WHERE [RowNumber] BETWEEN $offset AND $end ORDER BY [RowNumber]";
0d94fd 143
AM 144         return $query;
145     }
146
147     /**
8c2375 148      * Returns PDO DSN string from DSN array
0d94fd 149      */
AM 150     protected function dsn_string($dsn)
151     {
152         $params = array();
153         $result = 'sqlsrv:';
154
155         if ($dsn['hostspec']) {
156             $host = $dsn['hostspec'];
157
158             if ($dsn['port']) {
159                 $host .= ',' . $dsn['port'];
160             }
161             $params[] = 'Server=' . $host;
162         }
163
164         if ($dsn['database']) {
165             $params[] = 'Database=' . $dsn['database'];
166         }
167
168         if (!empty($params)) {
169             $result .= implode(';', $params);
170         }
171
172         return $result;
173     }
174 }