You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by je...@apache.org on 2010/06/16 08:38:37 UTC

svn commit: r955139 - in /incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src: main/java/org/apache/chemistry/opencmis/inmemory/query/ test/java/org/apache/chemistry/opencmis/inmemory/query/

Author: jens
Date: Wed Jun 16 06:38:37 2010
New Revision: 955139

URL: http://svn.apache.org/viewvc?rev=955139&view=rev
Log:
CMIS-216
implement  like, not like  in in-memory

Modified:
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryProcessor.java
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/EvalQueryTest.java
    incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/QueryTestDataCreator.java

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryProcessor.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryProcessor.java?rev=955139&r1=955138&r2=955139&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryProcessor.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/main/java/org/apache/chemistry/opencmis/inmemory/query/InMemoryQueryProcessor.java Wed Jun 16 06:38:37 2010
@@ -26,6 +26,7 @@ import java.util.Comparator;
 import java.util.GregorianCalendar;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
 
 import org.antlr.runtime.tree.Tree;
 import org.apache.chemistry.opencmis.commons.data.ObjectData;
@@ -35,6 +36,7 @@ import org.apache.chemistry.opencmis.com
 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
 import org.apache.chemistry.opencmis.commons.enums.Cardinality;
 import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
+import org.apache.chemistry.opencmis.commons.enums.PropertyType;
 import org.apache.chemistry.opencmis.commons.impl.dataobjects.ObjectListImpl;
 import org.apache.chemistry.opencmis.inmemory.TypeManager;
 import org.apache.chemistry.opencmis.inmemory.query.QueryObject.SortSpec;
@@ -481,19 +483,38 @@ public class InMemoryQueryProcessor impl
     }
 
     private boolean evalWhereIsNull(StoredObject so, Tree node, Tree child) {
-        throw new RuntimeException("Operator IS NULL not supported in InMemory server.");
+       Object propVal = getPropertyValue(child, so);
+       return null == propVal;
     }
 
     private boolean evalWhereIsNotNull(StoredObject so, Tree node, Tree child) {
-        throw new RuntimeException("Operator IS NOT NULL not supported in InMemory server.");
+        Object propVal = getPropertyValue(child, so);
+        return null != propVal;
     }
 
     private boolean evalWhereIsLike(StoredObject so, Tree node, Tree colNode, Tree StringNode) {
-        throw new RuntimeException("Operator LIKE not supported in InMemory server.");
+        Object rVal = onLiteral(StringNode);
+        if (!(rVal instanceof String))
+                throw new RuntimeException("LIKE operator requires String literal on right hand side.");
+        
+        ColumnReference colRef = getColumnReference(colNode);
+        TypeDefinition td = colRef.getTypeDefinition();
+        PropertyDefinition<?> pd = td.getPropertyDefinitions().get(colRef.getPropertyId());
+        PropertyType propType = pd.getPropertyType();
+        if (propType != PropertyType.STRING && propType != PropertyType.HTML &&  propType != PropertyType.ID &&
+                propType != PropertyType.URI)
+            throw new RuntimeException("Property type "+ propType.value() + " is not allowed FOR LIKE");
+        if (pd.getCardinality() != Cardinality.SINGLE)
+            throw new RuntimeException("LIKE is not allowed for multi-value properties ");
+        
+        String propVal = (String) so.getProperties().get(colRef.getPropertyId()).getFirstValue();
+        String pattern = translatePattern((String) rVal); // SQL to Java regex syntax
+        Pattern p = Pattern.compile(pattern);
+        return p.matcher(propVal).matches();
     }
 
     private boolean evalWhereIsNotLike(StoredObject so, Tree node, Tree colNode, Tree stringNode) {
-        throw new RuntimeException("Operator NOT LIKE not supported in InMemory server.");
+        return ! evalWhereIsLike(so, node, colNode, stringNode);
     }
 
     private boolean evalWhereContains(StoredObject so, Tree node, Tree colNode, Tree paramNode) {
@@ -508,13 +529,6 @@ public class InMemoryQueryProcessor impl
         throw new RuntimeException("Operator IN_TREE not supported in InMemory server.");
     }
 
-    private void checkLiteral(Tree node) {
-        int type = node.getType();
-        if (type != CMISQLLexerStrict.BOOL_LIT && type != CMISQLLexerStrict.NUM_LIT || type != CMISQLLexerStrict.STRING_LIT
-                || type != CMISQLLexerStrict.TIME_LIT)
-            throw new RuntimeException("Literal expected.");
-    }
-
     private Object onLiteral(Tree node) {
         int type = node.getType();
         String text = node.getText();
@@ -539,24 +553,16 @@ public class InMemoryQueryProcessor impl
     
     private Integer compareTo(StoredObject so, Tree leftChild, Tree rightChild) {
         Object rVal = onLiteral(rightChild);
+        
         //log.debug("retrieve node from where: " + System.identityHashCode(leftChild) + " is " + leftChild);
-        CmisSelector sel = queryObj.getColumnReference(leftChild.getTokenStartIndex());
-        if (null == sel)
-            throw new RuntimeException("Unknown property query name " + leftChild.getChild(0));
-        else if (sel instanceof ColumnReference) {
-            ColumnReference colRef = (ColumnReference) sel;
-            TypeDefinition td = colRef.getTypeDefinition();
-            PropertyDefinition<?> pd = td.getPropertyDefinitions().get(colRef.getPropertyId());
-            PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
-            if (null == lVal)
-                return null; // property is not set
-            else if (pd.getCardinality() == Cardinality.MULTI)
-                throw new RuntimeException("You can't query operators <, <=, ==, !=, >=, > on multi-value properties ");
-
+        ColumnReference colRef = getColumnReference(leftChild);
+        TypeDefinition td = colRef.getTypeDefinition();
+        PropertyDefinition<?> pd = td.getPropertyDefinitions().get(colRef.getPropertyId());
+        PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
+        if (lVal instanceof List<?>)
+            throw new RuntimeException("You can't query operators <, <=, ==, !=, >=, > on multi-value properties ");
+        else
             return compareTo(pd, lVal, rVal);
-        } else {
-            throw new RuntimeException("Unexpected numerical value function in where clause");
-        }
     }
     
     private int compareTo(PropertyDefinition<?> td, PropertyData<?> lVal, Object rVal) {
@@ -611,6 +617,68 @@ public class InMemoryQueryProcessor impl
         return 0;
     }
     
+    private ColumnReference getColumnReference(Tree columnNode) {
+        CmisSelector sel = queryObj.getColumnReference(columnNode.getTokenStartIndex());
+        if (null == sel)
+            throw new RuntimeException("Unknown property query name " + columnNode.getChild(0));
+        else if (sel instanceof ColumnReference)
+            return (ColumnReference) sel;
+        else
+            throw new RuntimeException("Unexpected numerical value function in where clause");
+    }
+    
+    private Object getPropertyValue(Tree columnNode, StoredObject so) {
+        ColumnReference colRef = getColumnReference(columnNode);
+        TypeDefinition td = colRef.getTypeDefinition();
+        PropertyDefinition<?> pd = td.getPropertyDefinitions().get(colRef.getPropertyId());
+        PropertyData<?> lVal = so.getProperties().get(colRef.getPropertyId());
+        if (null == lVal)
+            return null;
+        else {
+            if (pd.getCardinality() == Cardinality.SINGLE)
+                return null == lVal ? null : lVal.getFirstValue();
+            else
+                return lVal.getValues();
+        }                
+    }
+    
+    // translate SQL wildcards %, _ to Java regex syntax
+    public static String translatePattern(String wildcardString) {
+        int index = 0;
+        int start = 0;
+        StringBuffer res = new StringBuffer();
+        
+        while (index >= 0) {
+            index = wildcardString.indexOf('%', start);
+            if (index < 0) 
+                res.append(wildcardString.substring(start));
+            else if (index == 0 || index > 0 && wildcardString.charAt(index-1) != '\\') {
+                res.append(wildcardString.substring(start, index));
+                res.append(".*");
+            } else 
+                res.append(wildcardString.substring(start, index+1));
+            start = index+1;
+        }
+        wildcardString = res.toString();
+        
+        index = 0;
+        start = 0;
+        res = new StringBuffer();
+        
+        while (index >= 0) {
+            index = wildcardString.indexOf('_', start);
+            if (index < 0) 
+                res.append(wildcardString.substring(start));
+            else if (index == 0 || index > 0 && wildcardString.charAt(index-1) != '\\') {
+                res.append(wildcardString.substring(start, index));
+                res.append(".");
+            } else 
+                res.append(wildcardString.substring(start, index+1));
+            start = index+1;
+        }
+        return res.toString();
+    }
+    
     private void throwIncompatibleTypesException(Object o1, Object o2) {
         throw new RuntimeException("Incompatible Types to compare: " + o1 + " and " + o2);
     }

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/EvalQueryTest.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/EvalQueryTest.java?rev=955139&r1=955138&r2=955139&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/EvalQueryTest.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/EvalQueryTest.java Wed Jun 16 06:38:37 2010
@@ -42,6 +42,7 @@ import org.junit.Test;
 public class EvalQueryTest extends AbstractServiceTst {
     
     private static Log log = LogFactory.getLog(EvalQueryTest.class);
+    private QueryTestDataCreator dataCreator;
     
     @Before
     public void setUp() throws Exception {
@@ -50,8 +51,8 @@ public class EvalQueryTest extends Abstr
         super.setTypeCreatorClass(UnitTestTypeSystemCreator.class.getName());
         super.setUp();
         //create test data
-        QueryTestDataCreator dataCreator = new QueryTestDataCreator(fRepositoryId, fRootFolderId, fObjSvc );
-        dataCreator.createTestData();
+        dataCreator = new QueryTestDataCreator(fRepositoryId, fRootFolderId, fObjSvc );
+        dataCreator.createBasicTestData();
     }
 
     @After
@@ -470,6 +471,105 @@ public class EvalQueryTest extends Abstr
         assertTrue(resultContainsAtPos("delta", 2, res) || resultContainsAtPos("delta", 1, res) || resultContainsAtPos("delta", 0, res));
 }
 
+    @Test
+    public void testIsNull() {
+        dataCreator.createNullTestDocument();
+        String statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + PROP_ID_INT + " IS NULL";
+        ObjectList res = doQuery(statement);
+        assertEquals(1, res.getObjects().size());
+        assertTrue(resultContains("nulldoc", res));        
+    }
+    
+    @Test
+    public void testIsNotNull() {
+        dataCreator.createNullTestDocument();
+        String statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + PROP_ID_INT + " IS NOT NULL";
+        ObjectList res = doQuery(statement);
+        assertEquals(5, res.getObjects().size());
+        assertTrue(resultContains("alpha", res));        
+        assertTrue(resultContains("beta", res));        
+        assertTrue(resultContains("gamma", res));        
+        assertTrue(resultContains("delta", res));        
+        assertTrue(resultContains("epsilon", res));        
+    }
+    
+    @Test
+    public void patternTest() {
+        String res = InMemoryQueryProcessor.translatePattern("ABC%def");
+        assertEquals("ABC.*def", res);
+        res = InMemoryQueryProcessor.translatePattern("%abc");
+        assertEquals(".*abc", res);
+        res = InMemoryQueryProcessor.translatePattern("abc%");
+        assertEquals("abc.*", res);
+        res = InMemoryQueryProcessor.translatePattern("ABC\\%def");
+        assertEquals("ABC\\%def", res);
+        res = InMemoryQueryProcessor.translatePattern("\\%abc");
+        assertEquals("\\%abc", res);
+        res = InMemoryQueryProcessor.translatePattern("abc%def%ghi");
+        assertEquals("abc.*def.*ghi", res);
+        res = InMemoryQueryProcessor.translatePattern("abc%def\\%ghi%jkl");
+        assertEquals("abc.*def\\%ghi.*jkl", res);
+        
+        res = InMemoryQueryProcessor.translatePattern("ABC_def");
+        assertEquals("ABC.def", res);
+        res = InMemoryQueryProcessor.translatePattern("_abc");
+        assertEquals(".abc", res);
+        res = InMemoryQueryProcessor.translatePattern("abc_");
+        assertEquals("abc.", res);
+        res = InMemoryQueryProcessor.translatePattern("ABC\\_def");
+        assertEquals("ABC\\_def", res);
+        res = InMemoryQueryProcessor.translatePattern("\\_abc");
+        assertEquals("\\_abc", res);
+        res = InMemoryQueryProcessor.translatePattern("abc_def_ghi");
+        assertEquals("abc.def.ghi", res);
+        res = InMemoryQueryProcessor.translatePattern("abc_def\\_ghi_jkl");
+        assertEquals("abc.def\\_ghi.jkl", res);
+    }
+    
+    @Test
+    public void testLike() {
+        dataCreator.createLikeTestDocuments();
+        String statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " LIKE 'ABC%'";
+        ObjectList res = doQuery(statement);
+        assertEquals(2, res.getObjects().size());
+        assertTrue(resultContains("likedoc1", res));        
+        assertTrue(resultContains("likedoc2", res));        
+        
+        statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " LIKE '%ABC'";
+        res = doQuery(statement);
+        assertEquals(1, res.getObjects().size());
+        assertTrue(resultContains("likedoc3", res));        
+
+        statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " LIKE '%ABC%'";
+        res = doQuery(statement);
+        assertEquals(3, res.getObjects().size());
+        assertTrue(resultContains("likedoc1", res));        
+        assertTrue(resultContains("likedoc2", res));        
+        assertTrue(resultContains("likedoc3", res));
+        
+        statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " LIKE 'AB_DEF'";
+        res = doQuery(statement);
+        assertEquals(1, res.getObjects().size());
+        assertTrue(resultContains("likedoc1", res));        
+    }
+
+    @Test
+    public void testNotLike() {
+        dataCreator.createLikeTestDocuments();
+        String statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " NOT LIKE 'ABC%'";
+        ObjectList res = doQuery(statement);
+        assertEquals(6, res.getObjects().size());
+        assertTrue(resultContains("likedoc3", res));        
+        
+        statement = "SELECT * FROM " + COMPLEX_TYPE + " WHERE " + UnitTestTypeSystemCreator.PROP_ID_STRING + " NOT LIKE '%a'";
+        res = doQuery(statement);
+        assertEquals(4, res.getObjects().size());
+        assertTrue(resultContains("likedoc1", res));    
+        assertTrue(resultContains("likedoc1", res));    
+        assertTrue(resultContains("likedoc3", res));    
+        assertTrue(resultContains("epsilon", res));    
+    }
+    
     private ObjectList doQuery(String queryString) {
         log.debug("\nExecuting query: " + queryString);
         ObjectList res = fDiscSvc.query(fRepositoryId, queryString, false, false,

Modified: incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/QueryTestDataCreator.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/QueryTestDataCreator.java?rev=955139&r1=955138&r2=955139&view=diff
==============================================================================
--- incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/QueryTestDataCreator.java (original)
+++ incubator/chemistry/opencmis/trunk/chemistry-opencmis-server/chemistry-opencmis-server-inmemory/src/test/java/org/apache/chemistry/opencmis/inmemory/query/QueryTestDataCreator.java Wed Jun 16 06:38:37 2010
@@ -80,13 +80,13 @@ public class QueryTestDataCreator {
         fObjSvc = objSvc;
     }
     
-    public void createTestData() {
+    public void createBasicTestData() {
         createTestFolders();
-        createTestDocuments();
+        createBasicTestDocuments();
     }
 
     @SuppressWarnings("serial")
-    public void createTestDocuments() {
+    public void createBasicTestDocuments() {
 
         final GregorianCalendar gc1 = new GregorianCalendar(TZ);
         gc1.clear();
@@ -188,7 +188,42 @@ public class QueryTestDataCreator {
         folder11 = createFolder("Folder 11", folder1, FOLDER_TYPE, propertyMap3);
     }
     
+    @SuppressWarnings("serial")
+    public void createNullTestDocument() {
 
+        final Map<String, Object> propertyMap1 = 
+            new HashMap<String, Object>() {
+            { 
+                put(PROP_ID_STRING, "DocumentWithNulls");
+            }};           
+        createDocument("nulldoc", rootFolderId, COMPLEX_TYPE, propertyMap1);
+    }
+    
+    @SuppressWarnings("serial")
+    public void createLikeTestDocuments() {
+
+        final Map<String, Object> propertyMap1 = 
+            new HashMap<String, Object>() {
+            { 
+                put(PROP_ID_STRING, "ABCDEF");
+            }};           
+        createDocument("likedoc1", rootFolderId, COMPLEX_TYPE, propertyMap1);
+
+        final Map<String, Object> propertyMap2 = 
+            new HashMap<String, Object>() {
+            { 
+                put(PROP_ID_STRING, "ABC123");
+            }};           
+        createDocument("likedoc2", rootFolderId, COMPLEX_TYPE, propertyMap2);
+        
+        final Map<String, Object> propertyMap3 = 
+            new HashMap<String, Object>() {
+            { 
+                put(PROP_ID_STRING, "123ABC");
+            }};           
+        createDocument("likedoc3", rootFolderId, COMPLEX_TYPE, propertyMap3);
+    }
+    
     private String createFolder(String folderName, String parentFolderId, String typeId, Map<String, Object> properties) {
         Properties props = createFolderProperties(folderName, typeId, properties);
         String id = null;