Author: reschke
Date: Mon Feb  9 16:37:51 2015
New Revision: 1658458

URL: http://svn.apache.org/r1658458
Log:
OAK-2395 - MS SQL Support

MS SqlServer support - changes needed
- Changed column types and sizes
- Support for variation in limit, greatest, concat syntax

(ack Amit Jain)

Modified:
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
    
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBJDBCTools.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentStoreTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
    
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
    jackrabbit/oak/trunk/oak-parent/pom.xml

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
 Mon Feb  9 16:37:51 2015
@@ -324,6 +324,7 @@ public class RDBDocumentStore implements
 
     // implementation
 
+    enum FETCHFIRSTSYNTAX { FETCHFIRST, LIMIT, TOP};
 
     /**
      * Defines variation in the capabilities of different RDBs.
@@ -372,16 +373,44 @@ public class RDBDocumentStore implements
             }
 
             @Override
-            public boolean needsConcat() {
-                return true;
+            public FETCHFIRSTSYNTAX getFetchFirstSyntax() {
+                return FETCHFIRSTSYNTAX.LIMIT;
             }
 
             @Override
-            public boolean needsLimit() {
-                return true;
+            public String getConcatQueryString(int dataOctetLimit, int 
dataLength) {
+                return "CONCAT(DATA, ?)";
+            }
+        },
+
+        MSSQL("Microsoft SQL Server") {
+            @Override
+            public String getTableCreationStatement(String tableName) {
+                // see https://issues.apache.org/jira/browse/OAK-2395
+                return ("create table " + tableName + " (ID nvarchar(512) not 
null primary key, MODIFIED bigint, HASBINARY smallint, DELETEDONCE smallint, 
MODCOUNT bigint, CMODCOUNT bigint, DSIZE bigint, DATA nvarchar(4000), BDATA 
varbinary(max))");
             }
-        };
 
+            @Override
+            public FETCHFIRSTSYNTAX getFetchFirstSyntax() {
+                return FETCHFIRSTSYNTAX.TOP;
+            }
+
+            @Override
+            public String getConcatQueryString(int dataOctetLimit, int 
dataLength) {
+                /*
+                 * To avoid truncation when concatenating force an error when
+                 * limit is above the octet limit
+                 */
+                return "CASE WHEN LEN(DATA) <= " + (dataOctetLimit - 
dataLength) + " THEN (DATA + CAST(? AS nvarchar("
+                        + dataOctetLimit + "))) ELSE (DATA + CAST(DATA AS 
nvarchar(max))) END";
+
+            }
+
+            @Override
+            public String getGreatestQueryString(String column) {
+                return "(select MAX(mod) from (VALUES (" + column + "), (?)) 
AS ALLMOD(mod))";
+            }
+        };
 
         /**
          * If the primary column is encoded in bytes.
@@ -400,17 +429,36 @@ public class RDBDocumentStore implements
         }
 
         /**
-         * whether DB requires "CONCAT" over "||"
+         * Query syntax for "FETCH FIRST"
          */
-        public boolean needsConcat() {
-            return false;
+        public FETCHFIRSTSYNTAX getFetchFirstSyntax() {
+            return FETCHFIRSTSYNTAX.FETCHFIRST;
         }
 
         /**
-         * whether DB requires "LIMIT" instead of "FETCH FIRST"
+         * Returns the CONCAT function or its equivalent function or sub-query.
+         * Note that the function MUST NOT cause a truncated value to be
+         * written!
+         *
+         * @param dataOctetLimit
+         *            expected capacity of data column
+         * @param dataLength
+         *            length of string to be inserted
+         * 
+         * @return the concat query string
          */
-        public boolean needsLimit() {
-            return false;
+        public String getConcatQueryString(int dataOctetLimit, int dataLength) 
{
+            return "DATA || CAST(? AS varchar(" + dataOctetLimit + "))";
+        }
+
+        /**
+         * Returns the GREATEST function or its equivalent function or 
sub-query
+         * supported.
+         *
+         * @return the greatest query string
+         */
+        public String getGreatestQueryString(String column) {
+            return "GREATEST(" + column + ", ?)";
         }
 
         /**
@@ -1187,7 +1235,11 @@ public class RDBDocumentStore implements
 
     private List<RDBRow> dbQuery(Connection connection, String tableName, 
String minId, String maxId, String indexedProperty,
             long startValue, int limit) throws SQLException {
-        String t = "select ID, MODIFIED, MODCOUNT, CMODCOUNT, HASBINARY, 
DELETEDONCE, DATA, BDATA from " + tableName
+        String t = "select ";
+        if (limit != Integer.MAX_VALUE && this.db.getFetchFirstSyntax() == 
FETCHFIRSTSYNTAX.TOP) {
+            t += "TOP " + limit +  " ";
+        }
+        t += "ID, MODIFIED, MODCOUNT, CMODCOUNT, HASBINARY, DELETEDONCE, DATA, 
BDATA from " + tableName
                 + " where ID > ? and ID < ?";
         if (indexedProperty != null) {
             if (MODIFIED.equals(indexedProperty)) {
@@ -1207,9 +1259,20 @@ public class RDBDocumentStore implements
             }
         }
         t += " order by ID";
+
         if (limit != Integer.MAX_VALUE) {
-            t += this.db.needsLimit() ? (" LIMIT " + limit) : (" FETCH FIRST " 
+ limit + " ROWS ONLY");
+            switch (this.db.getFetchFirstSyntax()) {
+                case LIMIT:
+                    t += " LIMIT " + limit;
+                    break;
+                case FETCHFIRST:
+                    t += " FETCH FIRST " + limit + " ROWS ONLY";
+                    break;
+                default:
+                    break;
+            }
         }
+
         PreparedStatement stmt = connection.prepareStatement(t);
         List<RDBRow> result = new ArrayList<RDBRow>();
         try {
@@ -1291,11 +1354,9 @@ public class RDBDocumentStore implements
     private boolean dbAppendingUpdate(Connection connection, String tableName, 
String id, Long modified, Boolean hasBinary,
             Boolean deletedOnce, Long modcount, Long cmodcount, Long 
oldmodcount, String appendData) throws SQLException {
         StringBuilder t = new StringBuilder();
-        t.append("update "
-                + tableName
-                + " set MODIFIED = GREATEST(MODIFIED, ?), HASBINARY = ?, 
DELETEDONCE = ?, MODCOUNT = ?, CMODCOUNT = ?, DSIZE = DSIZE + ?, ");
-        t.append(this.db.needsConcat() ? "DATA = CONCAT(DATA, ?) " : "DATA = 
DATA || CAST(? AS varchar(" + this.dataLimitInOctets
-                + ")) ");
+        t.append("update " + tableName + " set MODIFIED = " + 
this.db.getGreatestQueryString("MODIFIED")
+                + ", HASBINARY = ?, DELETEDONCE = ?, MODCOUNT = ?, CMODCOUNT = 
?, DSIZE = DSIZE + ?, ");
+        t.append("DATA = " + 
this.db.getConcatQueryString(this.dataLimitInOctets, appendData.length()) + " 
");
         t.append("where ID = ?");
         if (oldmodcount != null) {
             t.append(" and MODCOUNT = ?");
@@ -1328,9 +1389,9 @@ public class RDBDocumentStore implements
     private boolean dbBatchedAppendingUpdate(Connection connection, String 
tableName, List<String> ids, Long modified,
             String appendData) throws SQLException {
         StringBuilder t = new StringBuilder();
-        t.append("update " + tableName + " set MODIFIED = GREATEST(MODIFIED, 
?), MODCOUNT = MODCOUNT + 1, DSIZE = DSIZE + ?, ");
-        t.append(this.db.needsConcat() ? "DATA = CONCAT(DATA, ?) " : "DATA = 
DATA || CAST(? AS varchar(" + this.dataLimitInOctets
-                + ")) ");
+        t.append("update " + tableName + " set MODIFIED = " + 
this.db.getGreatestQueryString("MODIFIED")
+                + ", MODCOUNT = MODCOUNT + 1, DSIZE = DSIZE + ?, ");
+        t.append("DATA = " + 
this.db.getConcatQueryString(this.dataLimitInOctets, appendData.length()) + " 
");
         t.append("where ID in (");
         for (int i = 0; i < ids.size(); i++) {
             if (i != 0) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBJDBCTools.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBJDBCTools.java?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBJDBCTools.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBJDBCTools.java
 Mon Feb  9 16:37:51 2015
@@ -50,6 +50,8 @@ public class RDBJDBCTools {
             return "com.mysql.jdbc.Driver";
         } else if ("oracle".equals(type)) {
             return "oracle.jdbc.OracleDriver";
+        } else if ("sqlserver".equals(type)) {
+            return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
         } else {
             return "";
         }

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentStoreTest.java?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/AbstractDocumentStoreTest.java
 Mon Feb  9 16:37:51 2015
@@ -80,7 +80,7 @@ public abstract class AbstractDocumentSt
         Collection<Object[]> result = new ArrayList<Object[]>();
         DocumentStoreFixture candidates[] = new DocumentStoreFixture[] { 
DocumentStoreFixture.MEMORY, DocumentStoreFixture.MONGO,
                 DocumentStoreFixture.RDB_H2, DocumentStoreFixture.RDB_PG, 
DocumentStoreFixture.RDB_DB2,
-                DocumentStoreFixture.RDB_MYSQL, 
DocumentStoreFixture.RDB_ORACLE };
+                DocumentStoreFixture.RDB_MYSQL, 
DocumentStoreFixture.RDB_ORACLE, DocumentStoreFixture.RDB_MSSQL };
 
         for (DocumentStoreFixture dsf : candidates) {
             if (dsf.isAvailable()) {

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/BasicDocumentStoreTest.java
 Mon Feb  9 16:37:51 2015
@@ -728,7 +728,7 @@ public class BasicDocumentStoreTest exte
             long cnt = 0;
             byte bdata[] = new byte[65536];
             String sdata = appendString;
-            boolean needsConcat = super.dsname.contains("MySQL");
+            boolean needsConcat = super.dsname.contains("MySQL") || 
super.dsname.contains("Microsoft SQL Server");
             int dataInChars = (super.dsname.contains("Oracle") ? 4000 : 16384);
             int dataInBytes = dataInChars / 3;
 

Modified: 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/plugins/document/DocumentStoreFixture.java
 Mon Feb  9 16:37:51 2015
@@ -41,6 +41,7 @@ public abstract class DocumentStoreFixtu
     public static final DocumentStoreFixture RDB_DB2 = new 
RDBFixture("RDB-DB2", "jdbc:db2://localhost:50000/OAK", "oak", "geheim");
     public static final DocumentStoreFixture RDB_MYSQL = new 
RDBFixture("RDB-MySQL", "jdbc:mysql://localhost:3306/oak", "root", "geheim");
     public static final DocumentStoreFixture RDB_ORACLE = new 
RDBFixture("RDB-Oracle", "jdbc:oracle:thin:@localhost:1521:orcl", "system", 
"geheim");
+    public static final DocumentStoreFixture RDB_MSSQL = new 
RDBFixture("RDB-MSSql", "jdbc:sqlserver://localhost:1433;databaseName=OAK", 
"sa", "geheim");
     public static final DocumentStoreFixture MONGO = new 
MongoFixture("mongodb://localhost:27017/oak");
 
     public static final String TABLEPREFIX = "dstest_";

Modified: jackrabbit/oak/trunk/oak-parent/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-parent/pom.xml?rev=1658458&r1=1658457&r2=1658458&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-parent/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-parent/pom.xml Mon Feb  9 16:37:51 2015
@@ -558,6 +558,21 @@
       </dependencies>
     </profile>
     <profile>
+      <!-- requires local copy of MS SqlServer JDBC driver deployed to Maven 
repo-->
+      <!-- for instance:
+        mvn install:install-file -Dfile=sqljdbc41.jar -Dpackaging=jar\
+          -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.1
+       -->
+      <id>rdb-mssql</id>
+      <dependencies>
+        <dependency>
+          <groupId>com.microsoft.sqlserver</groupId>
+          <artifactId>sqljdbc4</artifactId>
+          <version>4.1</version>
+        </dependency>
+      </dependencies>
+    </profile>
+    <profile>
       <!-- requires local copy of Oracle JDBC driver deployed to Maven repo-->
       <!-- for instance:
         mvn install:install-file -Dfile=ojdbc6.jar -Dpackaging=jar\


Reply via email to