From ed1d212ae2daea5e4bd043417610177093e99f19 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sat, 16 Jan 2016 03:03:51 -0500
Subject: [PATCH] Improved SVG cleanup code

---
 program/lib/Roundcube/rcube_db_mssql.php |   88 ++++++++++++++++++++++++++++++-------------
 1 files changed, 61 insertions(+), 27 deletions(-)

diff --git a/program/lib/Roundcube/rcube_db_mssql.php b/program/lib/Roundcube/rcube_db_mssql.php
index c95663c..4138b14 100644
--- a/program/lib/Roundcube/rcube_db_mssql.php
+++ b/program/lib/Roundcube/rcube_db_mssql.php
@@ -2,8 +2,6 @@
 
 /**
  +-----------------------------------------------------------------------+
- | program/include/rcube_db_mssql.php                                    |
- |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
  | Copyright (C) 2005-2012, The Roundcube Dev Team                       |
  |                                                                       |
@@ -14,12 +12,10 @@
  | PURPOSE:                                                              |
  |   Database wrapper class that implements PHP PDO functions            |
  |   for MS SQL Server database                                          |
- |                                                                       |
  +-----------------------------------------------------------------------+
  | Author: Aleksander Machniak <alec@alec.pl>                            |
  +-----------------------------------------------------------------------+
 */
-
 
 /**
  * Database independent query interface
@@ -33,37 +29,51 @@
     public $db_provider = 'mssql';
 
     /**
-     * Driver initialization
+     * Object constructor
+     *
+     * @param string $db_dsnw DSN for read/write operations
+     * @param string $db_dsnr Optional DSN for read only operations
+     * @param bool   $pconn   Enables persistent connections
      */
-    protected function init()
+    public function __construct($db_dsnw, $db_dsnr = '', $pconn = false)
     {
+        parent::__construct($db_dsnw, $db_dsnr, $pconn);
+
         $this->options['identifier_start'] = '[';
         $this->options['identifier_end'] = ']';
     }
 
     /**
-     * Character setting
+     * Driver-specific configuration of database connection
+     *
+     * @param array $dsn DSN for DB connections
+     * @param PDO   $dbh Connection handler
      */
-    protected function set_charset($charset)
+    protected function conn_configure($dsn, $dbh)
     {
-        // UTF-8 is default
+        // Set date format in case of non-default language (#1488918)
+        $dbh->query("SET DATEFORMAT ymd");
     }
 
     /**
      * Return SQL function for current time and date
      *
+     * @param int $interval Optional interval (in seconds) to add/subtract
+     *
      * @return string SQL function to use in query
      */
-    public function now()
+    public function now($interval = 0)
     {
+        if ($interval) {
+            $interval = intval($interval);
+            return "dateadd(second, $interval, getdate())";
+        }
+
         return "getdate()";
     }
 
     /**
      * Return SQL statement to convert a field value into a unix timestamp
-     *
-     * This method is deprecated and should not be used anymore due to limitations
-     * of timestamp functions in Mysql (year 2038 problem)
      *
      * @param string $field Field name
      *
@@ -104,25 +114,29 @@
     {
         $limit  = intval($limit);
         $offset = intval($offset);
+        $end    = $offset + $limit;
+
+        // query without OFFSET
+        if (!$offset) {
+            $query = preg_replace('/^SELECT\s/i', "SELECT TOP $limit ", $query);
+            return $query;
+        }
 
         $orderby = stristr($query, 'ORDER BY');
+        $offset += 1;
+
         if ($orderby !== false) {
-            $sort  = (stripos($orderby, ' desc') !== false) ? 'desc' : 'asc';
-            $order = str_ireplace('ORDER BY', '', $orderby);
-            $order = trim(preg_replace('/\bASC\b|\bDESC\b/i', '', $order));
+            $query = trim(substr($query, 0, -1 * strlen($orderby)));
+        }
+        else {
+            // it shouldn't happen, paging without sorting has not much sense
+            // @FIXME: I don't know how to build paging query without ORDER BY
+            $orderby = "ORDER BY 1";
         }
 
-        $query = preg_replace('/^SELECT\s/i', 'SELECT TOP ' . ($limit + $offset) . ' ', $query);
-
-        $query = 'SELECT * FROM (SELECT TOP ' . $limit . ' * FROM (' . $query . ') AS inner_tbl';
-        if ($orderby !== false) {
-            $query .= ' ORDER BY ' . $order . ' ';
-            $query .= (stripos($sort, 'asc') !== false) ? 'DESC' : 'ASC';
-        }
-        $query .= ') AS outer_tbl';
-        if ($orderby !== false) {
-            $query .= ' ORDER BY ' . $order . ' ' . $sort;
-        }
+        $query = preg_replace('/^SELECT\s/i', '', $query);
+        $query = "WITH paging AS (SELECT ROW_NUMBER() OVER ($orderby) AS [RowNumber], $query)"
+            . " SELECT * FROM paging WHERE [RowNumber] BETWEEN $offset AND $end ORDER BY [RowNumber]";
 
         return $query;
     }
@@ -153,4 +167,24 @@
 
         return $result;
     }
+
+    /**
+     * Parse SQL file and fix table names according to table prefix
+     */
+    protected function fix_table_names($sql)
+    {
+        if (!$this->options['table_prefix']) {
+            return $sql;
+        }
+
+        // replace sequence names, and other postgres-specific commands
+        $sql = preg_replace_callback(
+            '/((TABLE|(?<!ON )UPDATE|INSERT INTO|FROM(?! deleted)| ON(?! (DELETE|UPDATE|\[PRIMARY\]))'
+            . '|REFERENCES|CONSTRAINT|TRIGGER|INDEX)\s+(\[dbo\]\.)?[\[\]]*)([^\[\]\( \r\n]+)/',
+            array($this, 'fix_table_names_callback'),
+            $sql
+        );
+
+        return $sql;
+    }
 }

--
Gitblit v1.9.1