You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rcube_db_mssql.php 5.6KB

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