Return-Path: Delivered-To: apmail-incubator-chemistry-commits-archive@minotaur.apache.org Received: (qmail 67459 invoked from network); 16 Jun 2010 06:39:31 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 16 Jun 2010 06:39:31 -0000 Received: (qmail 61609 invoked by uid 500); 16 Jun 2010 06:39:31 -0000 Delivered-To: apmail-incubator-chemistry-commits-archive@incubator.apache.org Received: (qmail 61552 invoked by uid 500); 16 Jun 2010 06:39:29 -0000 Mailing-List: contact chemistry-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: chemistry-dev@incubator.apache.org Delivered-To: mailing list chemistry-commits@incubator.apache.org Received: (qmail 61544 invoked by uid 99); 16 Jun 2010 06:39:28 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Jun 2010 06:39:28 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 16 Jun 2010 06:39:24 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id C53F123888EA; Wed, 16 Jun 2010 06:38:37 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ Date: Wed, 16 Jun 2010 06:38:37 -0000 To: chemistry-commits@incubator.apache.org From: jens@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100616063837.C53F123888EA@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 propertyMap1 = + new HashMap() { + { + put(PROP_ID_STRING, "DocumentWithNulls"); + }}; + createDocument("nulldoc", rootFolderId, COMPLEX_TYPE, propertyMap1); + } + + @SuppressWarnings("serial") + public void createLikeTestDocuments() { + + final Map propertyMap1 = + new HashMap() { + { + put(PROP_ID_STRING, "ABCDEF"); + }}; + createDocument("likedoc1", rootFolderId, COMPLEX_TYPE, propertyMap1); + + final Map propertyMap2 = + new HashMap() { + { + put(PROP_ID_STRING, "ABC123"); + }}; + createDocument("likedoc2", rootFolderId, COMPLEX_TYPE, propertyMap2); + + final Map propertyMap3 = + new HashMap() { + { + put(PROP_ID_STRING, "123ABC"); + }}; + createDocument("likedoc3", rootFolderId, COMPLEX_TYPE, propertyMap3); + } + private String createFolder(String folderName, String parentFolderId, String typeId, Map properties) { Properties props = createFolderProperties(folderName, typeId, properties); String id = null;