You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by fg...@apache.org on 2009/07/07 20:19:09 UTC

svn commit: r791926 - in /incubator/chemistry/trunk/chemistry: chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/ chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/ chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simp...

Author: fguillaume
Date: Tue Jul  7 18:19:08 2009
New Revision: 791926

URL: http://svn.apache.org/viewvc?rev=791926&view=rev
Log:
CMIS-26: make simple implementation queries work correctly, using an ANTLR grammar and tree walker

Added:
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/CmisSqlSimpleWalker.g
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java   (with props)
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java   (with props)
Modified:
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlLexer.g
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlParser.g
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/impl/simple/SimpleConnection.java
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/xml/stax/XMLWriter.java
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/gunit/org/apache/chemistry/cmissql/CmisSql.testsuite
    incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/impl/simple/TestSimpleRepository.java
    incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlLexer.g
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlLexer.g?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlLexer.g (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlLexer.g Tue Jul  7 18:19:08 2009
@@ -21,6 +21,7 @@
 lexer grammar CmisSqlLexer;
 
 tokens {
+    TABLE;
     COL;
     LIST;
     FUNC;
@@ -28,6 +29,7 @@
     BIN_OP;
     BIN_OP_ANY;
     NOT_IN;
+    NOT_LIKE;
     IS_NULL;
     IS_NOT_NULL;
     ORDER_BY;

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlParser.g
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlParser.g?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlParser.g (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/cmissql/CmisSqlParser.g Tue Jul  7 18:19:08 2009
@@ -50,11 +50,7 @@
 package org.apache.chemistry.cmissql;
 }
 
-query: simple_table order_by_clause?;
-
-simple_table
-    : SELECT^ select_list from_clause where_clause?
-    ;
+query: SELECT^ select_list from_clause where_clause? order_by_clause?;
 
 select_list
     : STAR
@@ -99,10 +95,10 @@
 
 from_clause: FROM^ table_reference;
 
-// Use same trick as http://antlr.org/grammar/1057936474293/DmlSQL2.g to
-// remove left recursion.
-table_reference
-    : table_name ( AS!? correlation_name )?
+table_reference:
+      table_name
+    | table_name AS? correlation_name
+      -> ^(TABLE table_name correlation_name)
     | joined_table
     ;
 
@@ -171,7 +167,11 @@
     ;
 
 like_predicate:
-    column_reference NOT? LIKE^ STRING_LIT;
+      column_reference LIKE STRING_LIT
+        -> ^(BIN_OP LIKE column_reference STRING_LIT)
+    | column_reference NOT LIKE STRING_LIT
+        -> ^(BIN_OP NOT_LIKE column_reference STRING_LIT)
+    ;
 
 null_predicate:
     // second alternative commented out to remove left recursion for now.
@@ -210,8 +210,8 @@
     ;
 
 sort_specification:
-      column_name                        -> ASC  column_name
-    | column_name ( ord=ASC | ord=DESC ) -> $ord column_name
+      column_name -> column_name ASC
+    | column_name ( ASC | DESC )
     ;
 
 correlation_name:

Added: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/CmisSqlSimpleWalker.g
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/CmisSqlSimpleWalker.g?rev=791926&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/CmisSqlSimpleWalker.g (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/antlr3/org/apache/chemistry/impl/simple/CmisSqlSimpleWalker.g Tue Jul  7 18:19:08 2009
@@ -0,0 +1,271 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+/**
+ * CMIS-SQL tree grammar, walker for the simple implementation.
+ */
+tree grammar CmisSqlSimpleWalker;
+
+options {
+    tokenVocab = CmisSqlParser;
+    ASTLabelType = CommonTree;
+    output = AST;
+}
+
+@header {
+/*
+ * THIS FILE IS AUTO-GENERATED, DO NOT EDIT.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ *
+ * THIS FILE IS AUTO-GENERATED, DO NOT EDIT.
+ */
+package org.apache.chemistry.impl.simple;
+
+import org.apache.chemistry.impl.simple.SimpleData;
+}
+
+@members {
+    public SimpleData data;
+}
+
+query [SimpleData d] returns [String tableName, boolean matches]
+@init {
+    data = $d;
+}:
+    ^(SELECT select_list from_clause where_clause order_by_clause?)
+    {
+        $tableName = $from_clause.tableName;
+        $matches = $where_clause.matches;
+    }
+    ;
+
+select_list:
+      STAR
+    | ^(LIST select_sublist+)
+    ;
+
+select_sublist:
+      value_expression column_name?
+    | qualifier DOT STAR
+    ;
+
+value_expression returns [Object value]:
+      column_reference
+        {
+            $value = $column_reference.value;
+        }
+//    | string_value_function
+//    | numeric_value_function
+    ;
+
+column_reference returns [Object value]:
+    ^(COL qualifier? column_name)
+      {
+          String col = $column_name.start.getText();
+          $value = data.get(col); // TODO error if unknown prop
+      }
+    ;
+
+qualifier:
+      table_name
+//    | correlation_name
+    ;
+
+from_clause returns [String tableName]:
+    ^(FROM table_reference)
+      {
+          $tableName = $table_reference.tableName;
+      }
+    ;
+
+table_reference returns [String tableName]:
+      table_name
+        {
+            $tableName = $table_name.text;
+        }
+    | ^(TABLE table_name correlation_name)
+        {
+            $tableName = $table_name.text;
+        }
+    ;
+
+where_clause returns [boolean matches]:
+      ^(WHERE search_condition)
+        {
+            $matches = $search_condition.matches;
+        }
+    | /* nothing */
+        {
+            $matches = true;
+        }
+    ;
+
+search_condition returns [boolean matches]:
+      boolean_term
+        {
+            $matches = $boolean_term.matches;
+        }
+    | ^(OR (list+=boolean_term)+)
+        {
+            $matches = false;
+            for (boolean_term_return t : (List<boolean_term_return>) $list) {
+                if (t.matches) {
+                    $matches = true;
+                    break;
+                }
+            }
+        }
+    ;
+
+boolean_term returns [boolean matches]:
+      boolean_factor
+        {
+            $matches = $boolean_factor.matches;
+        }
+    | ^(AND (list+=boolean_factor)+)
+        {
+            $matches = true;
+            for (boolean_factor_return t : (List<boolean_factor_return>) $list) {
+                if (t.matches) {
+                    $matches = false;
+                    break;
+                }
+            }
+        }
+    ;
+
+boolean_factor returns [boolean matches]:
+      boolean_test
+        {
+            $matches = $boolean_test.matches;
+        }
+    | ^(NOT boolean_test)
+        {
+            $matches = ! $boolean_test.matches;
+        }
+    ;
+
+boolean_test returns [boolean matches]:
+      predicate
+        {
+            $matches = $predicate.matches;
+        }
+//    | search_condition
+    ;
+
+predicate returns [boolean matches]:
+      ^(UN_OP IS_NULL un_arg)
+        {
+            $matches = $un_arg.value == null;
+        }
+    | ^(UN_OP IS_NOT_NULL un_arg)
+        {
+            $matches = $un_arg.value != null;
+        }
+    | ^(BIN_OP bin_op arg1=bin_arg arg2=bin_arg)
+        {
+            int token = $bin_op.start.getType();
+            Object value1 = $arg1.value;
+            Object value2 = $arg2.value;
+            switch (token) {
+                case EQ:
+                    $matches = value1 != null && value1.equals(value2);
+                    break;
+                case NEQ:
+                    $matches = value1 != null && value2 != null && ! value1.equals(value2);
+                    break;
+                default:
+                    throw new UnwantedTokenException(token, input);
+            }
+        }
+//    | text_search_predicate
+//    | folder_predicate
+    ;
+
+un_arg returns [Object value]:
+    column_reference
+      {
+          $value = $column_reference.value;
+      }
+    ;
+
+bin_op:
+    EQ | NEQ | LT | GT | LTEQ | GTEQ | LIKE | NOT_LIKE;
+
+bin_arg returns [Object value]:
+      value_expression
+        {
+            $value = $value_expression.value;
+        }
+    | literal
+        {
+            $value = $literal.value;
+        }
+    | ^(LIST (list+=literal)+)
+        {
+            List<Object> ret = new ArrayList<Object>($list.size());
+            for (literal_return l : (List<literal_return>) $list) {
+                ret.add(l.value);
+            }
+            $value = ret;
+        }
+    ;
+
+literal returns [Object value]:
+      NUM_LIT
+        {
+            $value = Long.valueOf($NUM_LIT.text);
+        }
+    | STRING_LIT
+        {
+            String s = $STRING_LIT.text;
+            $value = s.substring(1, s.length() - 1);
+        }
+    ;
+
+order_by_clause:
+    ^(ORDER_BY sort_specification+)
+    ;
+
+sort_specification:
+    column_name ( ASC | DESC )
+    ;
+
+correlation_name:
+    ID;
+
+table_name:
+    ID;
+
+column_name:
+    ID;
+
+multi_valued_column_name:
+    ID;

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/impl/simple/SimpleConnection.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/impl/simple/SimpleConnection.java?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/impl/simple/SimpleConnection.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/impl/simple/SimpleConnection.java Tue Jul  7 18:19:08 2009
@@ -17,10 +17,10 @@
 package org.apache.chemistry.impl.simple;
 
 import java.io.ByteArrayInputStream;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
 import java.util.ArrayList;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -28,9 +28,15 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 
+import org.antlr.runtime.ANTLRInputStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenSource;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
 import org.apache.chemistry.BaseType;
 import org.apache.chemistry.CMISObject;
 import org.apache.chemistry.Connection;
@@ -51,6 +57,9 @@
 import org.apache.chemistry.Type;
 import org.apache.chemistry.Unfiling;
 import org.apache.chemistry.VersioningState;
+import org.apache.chemistry.cmissql.CmisSqlLexer;
+import org.apache.chemistry.cmissql.CmisSqlParser;
+import org.apache.chemistry.util.GregorianCalendar;
 
 public class SimpleConnection implements Connection, SPI {
 
@@ -165,12 +174,13 @@
                 } else if (Property.CREATED_BY.equals(name)) {
                     update.put(Property.CREATED_BY, "system"); // TODO
                 } else if (Property.CREATION_DATE.equals(name)) {
-                    update.put(Property.CREATION_DATE, Calendar.getInstance());
+                    update.put(Property.CREATION_DATE,
+                            GregorianCalendar.getInstance());
                 } else if (Property.LAST_MODIFIED_BY.equals(name)) {
                     update.put(Property.LAST_MODIFIED_BY, "system"); // TODO
                 } else if (Property.LAST_MODIFICATION_DATE.equals(name)) {
                     update.put(Property.LAST_MODIFICATION_DATE,
-                            Calendar.getInstance());
+                            GregorianCalendar.getInstance());
                 } else if (Property.IS_LATEST_VERSION.equals(name)) {
                     update.put(Property.IS_LATEST_VERSION, Boolean.TRUE);
                 } else if (Property.IS_LATEST_MAJOR_VERSION.equals(name)) {
@@ -501,33 +511,61 @@
             boolean searchAllVersions, boolean includeAllowableActions,
             boolean includeRelationships, int maxItems, int skipCount,
             boolean[] hasMoreItems) {
-
-        // TODO temporary implementation for unit testing of protocols
-
-        Matcher m = Pattern.compile("SELECT\\s+([*\\w, ]+)\\s+FROM\\s+(\\w+)",
-                Pattern.CASE_INSENSITIVE).matcher(statement);
-        if (!m.matches()) {
-            throw new RuntimeException("Cannot parse query: " + statement);
-        }
-        String props = m.group(1);
-        if (!"*".equals(props)) {
-            throw new RuntimeException(
-                    "Invalid query, must select all properties: " + statement);
-        }
-        String type = m.group(2);
-
+        // this implementation doesn't try to be very efficient...
         List<ObjectEntry> all = new ArrayList<ObjectEntry>();
+        String tableName = null;
         for (SimpleData data : repository.datas.values()) {
-            // TODO type inheritance not taken into account
-            String t = (String) data.get(SimpleProperty.TYPE_ID);
-            if (!t.equalsIgnoreCase(type)) {
-                continue;
+            if (tableName != null) {
+                // type already available: check early
+                if (!typeMatches(tableName, (String) data.get(Property.TYPE_ID))) {
+                    continue;
+                }
+            }
+            CmisSqlSimpleWalker.query_return ret = queryData(statement, data);
+            if (tableName == null) {
+                // first time: check late
+                tableName = ret.tableName.toLowerCase();
+                if (!typeMatches(tableName, (String) data.get(Property.TYPE_ID))) {
+                    continue;
+                }
+            }
+            if (ret.matches) {
+                all.add(new SimpleObjectEntry(data, this));
             }
-            all.add(new SimpleObjectEntry(data, this));
         }
         return subList(all, maxItems, skipCount, hasMoreItems);
     }
 
+    protected boolean typeMatches(String tableName, String typeId) {
+        do {
+            Type type = repository.getType(typeId);
+            if (tableName.equals(type.getQueryName().toLowerCase())) {
+                return true;
+            }
+            // check parent type
+            typeId = type.getParentId();
+        } while (typeId != null);
+        return false;
+    }
+
+    protected CmisSqlSimpleWalker.query_return queryData(String statement,
+            SimpleData data) {
+        try {
+            CharStream input = new ANTLRInputStream(new ByteArrayInputStream(
+                    statement.getBytes("UTF-8")));
+            TokenSource lexer = new CmisSqlLexer(input);
+            TokenStream tokens = new CommonTokenStream(lexer);
+            CommonTree tree = (CommonTree) new CmisSqlParser(tokens).query().getTree();
+            CommonTreeNodeStream nodes = new CommonTreeNodeStream(tree);
+            nodes.setTokenStream(tokens);
+            return new CmisSqlSimpleWalker(nodes).query(data);
+        } catch (IOException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        } catch (RecognitionException e) {
+            throw new RuntimeException("Cannot parse query: " + statement, e);
+        }
+    }
+
     public Collection<CMISObject> query(String statement,
             boolean searchAllVersions) {
         boolean[] hasMoreItems = new boolean[1];

Added: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java?rev=791926&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java Tue Jul  7 18:19:08 2009
@@ -0,0 +1,161 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+package org.apache.chemistry.util;
+
+import java.util.Calendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * A GregorianCalendar with a better toString method.
+ * <p>
+ * This way you don't have to pull you hair when debugging dates, or maps
+ * containing dates.
+ */
+public class GregorianCalendar extends java.util.GregorianCalendar {
+
+    private static final long serialVersionUID = 1L;
+
+    public static Calendar getInstance() {
+        return new GregorianCalendar();
+    }
+
+    public static Calendar getInstance(TimeZone zone) {
+        return new GregorianCalendar(zone);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar()
+     */
+    public GregorianCalendar() {
+        super();
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(TimeZone)
+     */
+    public GregorianCalendar(TimeZone zone) {
+        super(zone);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(Locale)
+     */
+    public GregorianCalendar(Locale aLocale) {
+        super(aLocale);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(TimeZone, Locale)
+     */
+    public GregorianCalendar(TimeZone zone, Locale aLocale) {
+        super(zone, aLocale);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(int, int, int)
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth) {
+        super(year, month, dayOfMonth);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(int, int, int, int,
+     *      int)
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth,
+            int hourOfDay, int minute) {
+        super(year, month, dayOfMonth, hourOfDay, minute);
+    }
+
+    /**
+     * @see java.util.GregorianCalendar#GregorianCalendar(int, int, int, int,
+     *      int, int)
+     */
+    public GregorianCalendar(int year, int month, int dayOfMonth,
+            int hourOfDay, int minute, int second) {
+        super(year, month, dayOfMonth, hourOfDay, minute, second);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder buf = new StringBuilder(47);
+        buf.append("GregorianCalendar(");
+        buf.append(get(YEAR));
+        buf.append('-');
+        int f = get(MONTH);
+        if (f < 9) {
+            buf.append('0');
+        }
+        buf.append(f + 1);
+        buf.append('-');
+        f = get(DATE);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append('T');
+        f = get(HOUR_OF_DAY);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append(':');
+        f = get(MINUTE);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append(':');
+        f = get(SECOND);
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append('.');
+        f = get(MILLISECOND);
+        if (f < 100) {
+            buf.append('0');
+        }
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        char sign;
+        int offset = getTimeZone().getOffset(getTimeInMillis()) / 60000;
+        if (offset < 0) {
+            offset = -offset;
+            sign = '-';
+        } else {
+            sign = '+';
+        }
+        buf.append(sign);
+        f = offset / 60;
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        f = offset % 60;
+        if (f < 10) {
+            buf.append('0');
+        }
+        buf.append(f);
+        buf.append(')');
+        return buf.toString();
+    }
+
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/util/GregorianCalendar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/xml/stax/XMLWriter.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/xml/stax/XMLWriter.java?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/xml/stax/XMLWriter.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/main/java/org/apache/chemistry/xml/stax/XMLWriter.java Tue Jul  7 18:19:08 2009
@@ -27,6 +27,8 @@
 
 import javax.xml.namespace.QName;
 
+import org.apache.chemistry.util.GregorianCalendar;
+
 // This file contains code from org.apache.commons.betwixt.XMLUtils
 /**
  *
@@ -393,7 +395,7 @@
      */
     public static String formatDate(Date date) {
         StringBuilder sb = new StringBuilder(24);
-        Calendar c = Calendar.getInstance(TIMEZONE_UTC);
+        Calendar c = GregorianCalendar.getInstance(TIMEZONE_UTC);
         c.setTime(date);
         sb.append(c.get(Calendar.YEAR));
         sb.append('-');

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/gunit/org/apache/chemistry/cmissql/CmisSql.testsuite
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/gunit/org/apache/chemistry/cmissql/CmisSql.testsuite?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/gunit/org/apache/chemistry/cmissql/CmisSql.testsuite (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/gunit/org/apache/chemistry/cmissql/CmisSql.testsuite Tue Jul  7 18:19:08 2009
@@ -64,15 +64,20 @@
 "'abc'" OK
 
 order_by_clause:
-"ORDER BY foo" -> (ORDER_BY ASC foo)
-"ORDER BY foo ASC" -> (ORDER_BY ASC foo)
-"ORDER BY foo DESC" -> (ORDER_BY DESC foo)
-"ORDER BY foo, bar DESC" -> (ORDER_BY ASC foo DESC bar)
+"ORDER BY foo" -> (ORDER_BY foo ASC)
+"ORDER BY foo ASC" -> (ORDER_BY foo ASC)
+"ORDER BY foo DESC" -> (ORDER_BY foo DESC)
+"ORDER BY foo, bar DESC" -> (ORDER_BY foo ASC bar DESC)
 
 column_reference:
 "foo" -> (COL foo)
 "bar.foo" -> (COL bar foo)
 
+table_reference:
+"foo" -> "foo"
+"foo bar" -> (TABLE foo bar)
+"foo AS bar" -> (TABLE foo bar)
+
 in_predicate:
 "foo IN ( 'a', 'b', 'c')" -> (BIN_OP IN (COL foo) (LIST 'a' 'b' 'c'))
 "foo NOT IN ( 1, 2, 3)" -> (BIN_OP NOT_IN (COL foo) (LIST 1 2 3))
@@ -107,7 +112,7 @@
 query:
 "SELECT * FROM Document" -> (SELECT * (FROM Document))
 "SELECT a, b, c FROM Document" -> (SELECT (LIST (COL a) (COL b) (COL c)) (FROM Document))
-"SELECT a, b FROM Document ORDER BY a, b" -> (SELECT (LIST (COL a) (COL b)) (FROM Document)) (ORDER_BY ASC a ASC b)
+"SELECT a, b FROM Document ORDER BY a, b" -> (SELECT (LIST (COL a) (COL b)) (FROM Document) (ORDER_BY a ASC b ASC))
 
 
 // Examples from the specs.

Modified: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/impl/simple/TestSimpleRepository.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/impl/simple/TestSimpleRepository.java?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/impl/simple/TestSimpleRepository.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/impl/simple/TestSimpleRepository.java Tue Jul  7 18:19:08 2009
@@ -214,4 +214,25 @@
         assertNull(conn.getObject(d1, ReturnVersion.THIS));
     }
 
+    public void testBasicQuery() {
+        Connection conn = repo.getConnection(null);
+        Folder root = conn.getRootFolder();
+        Document d1 = root.newDocument("doc");
+        d1.save();
+
+        Collection<CMISObject> res = conn.query("SELECT * FROM Folder", false);
+        assertEquals(1, res.size()); // the root
+        res = conn.query("SELECT * FROM fold", false);
+        assertEquals(0, res.size());
+        res = conn.query("SELECT * FROM doc", false);
+        assertEquals(1, res.size());
+        res = conn.query("SELECT * FROM Folder WHERE Name = 'CMIS_Root_Folder'",
+                false);
+        assertEquals(1, res.size());
+        res = conn.query("SELECT * FROM doc WHERE ObjectId = 'nosuchid'", false);
+        assertEquals(0, res.size());
+        res = conn.query("SELECT * FROM doc WHERE ObjectId <> '123'", false);
+        assertEquals(1, res.size());
+    }
+
 }

Added: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java?rev=791926&view=auto
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java (added)
+++ incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java Tue Jul  7 18:19:08 2009
@@ -0,0 +1,52 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Authors:
+ *     Florent Guillaume, Nuxeo
+ */
+package org.apache.chemistry.util;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+public class TestGregorianCalendar extends TestCase {
+
+    public void testToString1() {
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT+07:30"));
+        cal.set(Calendar.YEAR, 2009);
+        cal.set(Calendar.MONTH, 0);
+        cal.set(Calendar.DATE, 2);
+        cal.set(Calendar.HOUR_OF_DAY, 3);
+        cal.set(Calendar.MINUTE, 4);
+        cal.set(Calendar.SECOND, 5);
+        cal.set(Calendar.MILLISECOND, 6);
+        assertEquals("GregorianCalendar(2009-01-02T03:04:05.006+0730)",
+                cal.toString());
+    }
+
+    public void testToString2() {
+        Calendar cal = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT-06:00"));
+        cal.set(Calendar.YEAR, 2008);
+        cal.set(Calendar.MONTH, 11);
+        cal.set(Calendar.DATE, 31);
+        cal.set(Calendar.HOUR_OF_DAY, 23);
+        cal.set(Calendar.MINUTE, 59);
+        cal.set(Calendar.SECOND, 59);
+        cal.set(Calendar.MILLISECOND, 999);
+        assertEquals("GregorianCalendar(2008-12-31T23:59:59.999-0600)",
+                cal.toString());
+    }
+
+}

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java
------------------------------------------------------------------------------
    svn:keywords = Id

Propchange: incubator/chemistry/trunk/chemistry/chemistry-commons/src/test/java/org/apache/chemistry/util/TestGregorianCalendar.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java
URL: http://svn.apache.org/viewvc/incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java?rev=791926&r1=791925&r2=791926&view=diff
==============================================================================
--- incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java (original)
+++ incubator/chemistry/trunk/chemistry/chemistry-jcr/src/main/java/org/apache/chemistry/jcr/JcrNewDocument.java Tue Jul  7 18:19:08 2009
@@ -20,7 +20,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.Serializable;
-import java.util.Calendar;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
@@ -31,6 +30,7 @@
 import org.apache.chemistry.ContentStream;
 import org.apache.chemistry.Document;
 import org.apache.chemistry.Folder;
+import org.apache.chemistry.util.GregorianCalendar;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.jackrabbit.JcrConstants;
@@ -172,7 +172,8 @@
                 content.setProperty(JcrConstants.JCR_MIMETYPE, "application/octet-stream");
                 content.setProperty(JcrConstants.JCR_DATA, new ByteArrayInputStream(new byte[0]));
             }
-            content.setProperty(JcrConstants.JCR_LASTMODIFIED, Calendar.getInstance());
+            content.setProperty(JcrConstants.JCR_LASTMODIFIED,
+                    GregorianCalendar.getInstance());
 
             for (String key : values.keySet()) {
                 node.setProperty(key, values.get(key).toString());