You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2017/03/20 10:18:26 UTC

[1/3] cayenne git commit: CAY-2269 Add support for date/time components extraction in expression functions

Repository: cayenne
Updated Branches:
  refs/heads/master e56a93f4f -> 05a772502


http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimestampTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimestampTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimestampTest.java
new file mode 100644
index 0000000..7b5fd0d
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimestampTest.java
@@ -0,0 +1,54 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.util.Date;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @since 4.0
+ */
+public class ASTCurrentTimestampTest {
+
+    @Test
+    public void testParse() {
+        Expression exp2 = ExpressionFactory.exp("currentTimestamp()");
+        assertTrue(exp2 instanceof ASTCurrentTimestamp);
+
+        Expression exp3 = ExpressionFactory.exp("now()");
+        assertTrue(exp3 instanceof ASTCurrentTimestamp);
+
+        assertEquals("currentTimestamp()", exp2.toString());
+        assertEquals("currentTimestamp()", exp3.toString());
+    }
+
+    @Test
+    public void testEvaluate() {
+        Expression exp = new ASTCurrentTimestamp();
+        Object result = exp.evaluate(new Object());
+        assertTrue(result instanceof Date);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractIT.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractIT.java
new file mode 100644
index 0000000..7ebbfba
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractIT.java
@@ -0,0 +1,240 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.util.Calendar;
+import java.util.List;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.query.ObjectSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.testdo.date_time.DateTestEntity;
+import org.apache.cayenne.unit.UnitDbAdapter;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * @since 4.0
+ */
+@UseServerRuntime(CayenneProjects.DATE_TIME_PROJECT)
+public class ASTExtractIT extends ServerCase {
+
+    @Inject
+    private ObjectContext context;
+
+    @Inject
+    private DBHelper dbHelper;
+
+    @Inject
+    private UnitDbAdapter unitDbAdapter;
+
+    @Before
+    public void createDataSet() throws Exception {
+        Calendar cal = Calendar.getInstance();
+        cal.set(Calendar.MILLISECOND, 0);
+
+        DateTestEntity o1 = context.newObject(DateTestEntity.class);
+        cal.set(2015, Calendar.FEBRUARY, 28,
+                0, 0, 0);
+        o1.setDateColumn(cal.getTime());
+
+        cal.set(2017, Calendar.MARCH, 30,
+                0, 0, 0);
+        o1.setTimeColumn(cal.getTime());
+
+        cal.set(Calendar.DAY_OF_MONTH, 29);
+        o1.setTimestampColumn(cal.getTime());
+
+        DateTestEntity o2 = context.newObject(DateTestEntity.class);
+        cal.set(2016, Calendar.MARCH, 29,
+                0, 0, 0);
+        o2.setDateColumn(cal.getTime());
+
+        cal.set(2017, Calendar.APRIL, 1,
+                23, 59, 39);
+        o2.setTimeColumn(cal.getTime());
+
+        cal.set(Calendar.DAY_OF_MONTH, 2);
+        o2.setTimestampColumn(cal.getTime());
+
+        context.commitChanges();
+    }
+
+
+    @Test
+    public void testYear() {
+        Expression exp = ExpressionFactory.exp("year(dateColumn) = 2015");
+
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.YEAR)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testMonth() {
+        Expression exp = ExpressionFactory.exp("month(dateColumn) = 3");
+
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.MONTH)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testWeek() {
+        // 13 or 14 depends of first day in week in current db
+        Expression exp = ExpressionFactory.exp("week(dateColumn) in (13, 14)");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.WEEK)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testDayOfYear() {
+        // day can start from 0
+        Expression exp = ExpressionFactory.exp("dayOfYear(dateColumn) in (59, 58)");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.DAY_OF_YEAR)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testDayOfYearSelect() {
+        Property<Integer> dayOfYear = Property.create(
+                FunctionExpressionFactory.yearExp(DateTestEntity.DATE_COLUMN.path()), Integer.class);
+
+        try {
+            List<Integer> res = ObjectSelect.query(DateTestEntity.class).column(dayOfYear).select(context);
+            assertEquals(2, res.size());
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.DAY_OF_YEAR)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testDay() {
+        Expression exp = ExpressionFactory.exp("day(dateColumn) = 28");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.DAY)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testDayOfMonth() {
+        Expression exp = ExpressionFactory.exp("dayOfMonth(dateColumn) = 28");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.DAY_OF_MONTH)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testDayOfWeek() {
+        Expression exp = ExpressionFactory.exp("dayOfWeek(dateColumn) in (2, 3)");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.DAY_OF_WEEK)) {
+                throw e;
+            }
+        }
+    }
+
+    @Test
+    public void testHour() {
+        Expression exp = ExpressionFactory.exp("hour(timestampColumn) = 23");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.HOUR)) {
+                throw e;
+            } // else ok
+        }
+    }
+
+    @Test
+    public void testMinute() {
+        Expression exp = ExpressionFactory.exp("minute(timestampColumn) = 59");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.MINUTE)) {
+                throw e;
+            }
+        }
+    }
+
+    @Test
+    public void testSecond() {
+        Expression exp = ExpressionFactory.exp("second(timestampColumn) = 39");
+        try {
+            long res = ObjectSelect.query(DateTestEntity.class, exp).selectCount(context);
+            assertEquals(1, res);
+        } catch (CayenneRuntimeException e) {
+            if(unitDbAdapter.supportsExtractPart(ASTExtract.DateTimePart.SECOND)) {
+                throw e;
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractTest.java
new file mode 100644
index 0000000..1787636
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTExtractTest.java
@@ -0,0 +1,162 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.exp.FunctionExpressionFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @since 4.0
+ */
+public class ASTExtractTest {
+
+    @Test
+    public void testYear() {
+        String expStr = "year(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.yearExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testMonth() {
+        String expStr = "month(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.monthExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testWeek() {
+        String expStr = "week(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.weekExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testDayOfYear() {
+        String expStr = "dayOfYear(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.dayOfYearExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testDay() {
+        String expStr = "day(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+
+        assertTrue(expParsed instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+    }
+
+    @Test
+    public void testDayOfMonth() {
+        String expStr = "dayOfMonth(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.dayOfMonthExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testDayOfWeek() {
+        String expStr = "dayOfWeek(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.dayOfWeekExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testHour() {
+        String expStr = "hour(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.hourExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testMinute() {
+        String expStr = "minute(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.minuteExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+    @Test
+    public void testSecond() {
+        String expStr = "second(dateColumn)";
+        Expression expParsed = ExpressionFactory.exp(expStr);
+        Expression expFromFactory = FunctionExpressionFactory.secondExp("dateColumn");
+
+        assertTrue(expParsed instanceof ASTExtract);
+        assertTrue(expFromFactory instanceof ASTExtract);
+
+        assertEquals(expStr, expParsed.toString());
+        assertEquals(expStr, expFromFactory.toString());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/unit/DerbyUnitDbAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/DerbyUnitDbAdapter.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/DerbyUnitDbAdapter.java
index c64f1b2..409c861 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/DerbyUnitDbAdapter.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/DerbyUnitDbAdapter.java
@@ -20,6 +20,7 @@
 package org.apache.cayenne.unit;
 
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.exp.parser.ASTExtract;
 
 /**
  * 
@@ -55,4 +56,15 @@ public class DerbyUnitDbAdapter extends UnitDbAdapter {
     public boolean supportsExpressionInHaving() {
         return false;
     }
+
+    @Override
+    public boolean supportsExtractPart(ASTExtract.DateTimePart part) {
+        switch (part) {
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+            case WEEK:
+                return false;
+        }
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/unit/FrontBaseUnitDbAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/FrontBaseUnitDbAdapter.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/FrontBaseUnitDbAdapter.java
index eb987f4..123ff8d 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/FrontBaseUnitDbAdapter.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/FrontBaseUnitDbAdapter.java
@@ -23,6 +23,7 @@ import java.sql.Connection;
 import java.util.Collection;
 
 import org.apache.cayenne.dba.DbAdapter;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.map.DataMap;
 
 /**
@@ -86,4 +87,14 @@ public class FrontBaseUnitDbAdapter extends UnitDbAdapter {
     public boolean supportsExpressionInHaving() {
         return false;
     }
+
+    public boolean supportsExtractPart(ASTExtract.DateTimePart part) {
+        switch (part) {
+            case WEEK:
+            case DAY_OF_YEAR:
+            case DAY_OF_WEEK:
+                return false;
+        }
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/unit/UnitDbAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/UnitDbAdapter.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/UnitDbAdapter.java
index 87ca60c..a4f22f7 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/UnitDbAdapter.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/UnitDbAdapter.java
@@ -25,6 +25,7 @@ import org.apache.cayenne.configuration.RuntimeProperties;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.dba.QuotingStrategy;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.DbEntity;
 import org.apache.cayenne.map.Procedure;
@@ -398,4 +399,8 @@ public class UnitDbAdapter {
     public boolean supportsSelectBooleanExpression() {
         return true;
     }
+
+    public boolean supportsExtractPart(ASTExtract.DateTimePart part) {
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java
index 94a2708..5864b77 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/unit/di/server/ServerCaseDataSourceInfoProvider.java
@@ -97,7 +97,7 @@ public class ServerCaseDataSourceInfoProvider implements Provider<DataSourceInfo
         sqlite.setAdapterClassName(SQLiteAdapter.class.getName());
         sqlite.setUserName("sa");
         sqlite.setPassword("");
-        sqlite.setDataSourceUrl("jdbc:sqlite:file:memdb?mode=memory&cache=shared");
+        sqlite.setDataSourceUrl("jdbc:sqlite:file:memdb?mode=memory&cache=shared&date_class=text");
         sqlite.setJdbcDriver("org.sqlite.JDBC");
         sqlite.setMinConnections(ConnectionProperties.MIN_CONNECTIONS);
         sqlite.setMaxConnections(ConnectionProperties.MAX_CONNECTIONS);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index 9f5e3c3..ebe1207 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -18,6 +18,7 @@ CAY-2258 DI: type-safe binding of List and Map
 CAY-2266 Move EventBridge implementations into autoloadable modules
 CAY-2267 Contribute lifecycle events listeners via DI
 CAY-2259 QueryCache: support for referencing type-safe caches
+CAY-2269 Add support for date/time components extraction in expression functions
 CAY-2270 Update function support in expression parser
 
 Bug Fixes:


[2/3] cayenne git commit: CAY-2269 Add support for date/time components extraction in expression functions

Posted by nt...@apache.org.
http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
index a5b3d00..e1d31ad 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTokenManager.java
@@ -108,181 +108,189 @@ private final int jjStopStringLiteralDfa_0(int pos, long active0, long active1)
    switch (pos)
    {
       case 0:
-         if ((active0 & 0x387f4f00004e006L) != 0L)
+         if ((active0 & 0x18030000000000L) != 0L)
          {
-            jjmatchedKind = 59;
-            return 74;
+            jjmatchedKind = 69;
+            return 36;
          }
          if ((active0 & 0x80000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             return 6;
          }
          if ((active0 & 0x8L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             return 63;
          }
-         if ((active0 & 0x18030000000000L) != 0L)
+         if ((active0 & 0xffc7f4f00004e006L) != 0L || (active1 & 0xeL) != 0L)
          {
-            jjmatchedKind = 59;
-            return 36;
+            jjmatchedKind = 69;
+            return 74;
          }
          return -1;
       case 1:
-         if ((active0 & 0x80000000000L) != 0L)
+         if ((active0 & 0x18000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 1;
-            return 5;
+            return 35;
          }
-         if ((active0 & 0x387f7f000046004L) != 0L)
+         if ((active0 & 0x8002L) != 0L)
+            return 74;
+         if ((active0 & 0x80000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 1;
-            return 74;
+            return 5;
          }
          if ((active0 & 0x8L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 1;
             return 64;
          }
-         if ((active0 & 0x8002L) != 0L)
-            return 74;
-         if ((active0 & 0x18000000000000L) != 0L)
+         if ((active0 & 0xffc7f7f000046004L) != 0L || (active1 & 0xeL) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 1;
-            return 35;
+            return 74;
          }
          return -1;
       case 2:
-         if ((active0 & 0x282ff0000046000L) != 0L)
+         if ((active0 & 0x5e0500f00000000cL) != 0L)
+            return 74;
+         if ((active0 & 0xa1c2ff0000046000L) != 0L || (active1 & 0xaL) != 0L)
          {
-            jjmatchedKind = 59;
-            jjmatchedPos = 2;
+            if (jjmatchedPos != 2)
+            {
+               jjmatchedKind = 69;
+               jjmatchedPos = 2;
+            }
             return 74;
          }
          if ((active0 & 0x18000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
-            jjmatchedPos = 2;
+            if (jjmatchedPos != 2)
+            {
+               jjmatchedKind = 69;
+               jjmatchedPos = 2;
+            }
             return 34;
          }
-         if ((active0 & 0x500f00000000cL) != 0L)
-            return 74;
          return -1;
       case 3:
-         if ((active0 & 0x200f70000040000L) != 0L)
+         if ((active0 & 0x2142080000006000L) != 0L)
+            return 74;
+         if ((active0 & 0x18000000000000L) != 0L)
          {
             if (jjmatchedPos != 3)
             {
-               jjmatchedKind = 59;
+               jjmatchedKind = 69;
                jjmatchedPos = 3;
             }
-            return 74;
+            return 33;
          }
-         if ((active0 & 0x18000000000000L) != 0L)
+         if ((active0 & 0xda80f70000040000L) != 0L || (active1 & 0x8L) != 0L)
          {
             if (jjmatchedPos != 3)
             {
-               jjmatchedKind = 59;
+               jjmatchedKind = 69;
                jjmatchedPos = 3;
             }
-            return 33;
-         }
-         if ((active0 & 0x2080000006000L) != 0L)
             return 74;
+         }
          return -1;
       case 4:
+         if ((active0 & 0x80310000000000L) != 0L)
+            return 74;
          if ((active0 & 0x18000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 4;
             return 32;
          }
-         if ((active0 & 0xc60000044000L) != 0L)
+         if ((active0 & 0xda00c60000044000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 4;
             return 74;
          }
-         if ((active0 & 0x310000000000L) != 0L)
-            return 74;
          return -1;
       case 5:
-         if ((active0 & 0x40000044000L) != 0L)
+         if ((active0 & 0x18000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 5;
-            return 74;
+            return 31;
          }
-         if ((active0 & 0xc20000000000L) != 0L)
+         if ((active0 & 0xc000c20000000000L) != 0L)
             return 74;
-         if ((active0 & 0x18000000000000L) != 0L)
+         if ((active0 & 0x1a00040000044000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 5;
-            return 31;
+            return 74;
          }
          return -1;
       case 6:
-         if ((active0 & 0x40000004000L) != 0L)
+         if ((active0 & 0x18000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 6;
-            return 74;
+            return 30;
          }
          if ((active0 & 0x40000L) != 0L)
             return 74;
-         if ((active0 & 0x18000000000000L) != 0L)
+         if ((active0 & 0x1a00040000004000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 6;
-            return 30;
+            return 74;
          }
          return -1;
       case 7:
-         if ((active0 & 0x8040000004000L) != 0L)
+         if ((active0 & 0x1a08040000004000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 7;
             return 74;
          }
          if ((active0 & 0x10000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 7;
             return 29;
          }
          return -1;
       case 8:
+         if ((active0 & 0x1200040000000000L) != 0L)
+            return 74;
          if ((active0 & 0x10000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 8;
             return 28;
          }
-         if ((active0 & 0x8000000004000L) != 0L)
+         if ((active0 & 0x808000000004000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 8;
             return 74;
          }
-         if ((active0 & 0x40000000000L) != 0L)
-            return 74;
          return -1;
       case 9:
+         if ((active0 & 0x800000000000000L) != 0L)
+            return 74;
          if ((active0 & 0x10000000000000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 9;
             return 27;
          }
          if ((active0 & 0x8000000004000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 9;
             return 74;
          }
@@ -290,19 +298,19 @@ private final int jjStopStringLiteralDfa_0(int pos, long active0, long active1)
       case 10:
          if ((active0 & 0x10000000000000L) != 0L)
             return 26;
+         if ((active0 & 0x8000000000000L) != 0L)
+            return 74;
          if ((active0 & 0x4000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 10;
             return 74;
          }
-         if ((active0 & 0x8000000000000L) != 0L)
-            return 74;
          return -1;
       case 11:
          if ((active0 & 0x4000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 11;
             return 74;
          }
@@ -310,7 +318,7 @@ private final int jjStopStringLiteralDfa_0(int pos, long active0, long active1)
       case 12:
          if ((active0 & 0x4000L) != 0L)
          {
-            jjmatchedKind = 59;
+            jjmatchedKind = 69;
             jjmatchedPos = 12;
             return 74;
          }
@@ -335,21 +343,21 @@ private int jjMoveStringLiteralDfa0_0()
    {
       case 33:
          jjmatchedKind = 4;
-         return jjMoveStringLiteralDfa1_0(0x80L);
+         return jjMoveStringLiteralDfa1_0(0x80L, 0x0L);
       case 34:
-         return jjStopAtPos(0, 64);
+         return jjStopAtPos(0, 74);
       case 36:
-         return jjStopAtPos(0, 54);
+         return jjStopAtPos(0, 64);
       case 38:
          return jjStopAtPos(0, 22);
       case 39:
-         return jjStopAtPos(0, 63);
+         return jjStopAtPos(0, 73);
       case 40:
          return jjStopAtPos(0, 16);
       case 41:
          return jjStopAtPos(0, 17);
       case 42:
-         return jjStopAtPos(0, 58);
+         return jjStopAtPos(0, 68);
       case 43:
          return jjStopAtPos(0, 25);
       case 44:
@@ -360,41 +368,47 @@ private int jjMoveStringLiteralDfa0_0()
          return jjStopAtPos(0, 27);
       case 60:
          jjmatchedKind = 10;
-         return jjMoveStringLiteralDfa1_0(0x800300L);
+         return jjMoveStringLiteralDfa1_0(0x800300L, 0x0L);
       case 61:
          jjmatchedKind = 5;
-         return jjMoveStringLiteralDfa1_0(0x40L);
+         return jjMoveStringLiteralDfa1_0(0x40L, 0x0L);
       case 62:
          jjmatchedKind = 11;
-         return jjMoveStringLiteralDfa1_0(0x1001000L);
+         return jjMoveStringLiteralDfa1_0(0x1001000L, 0x0L);
       case 94:
          return jjStopAtPos(0, 21);
       case 97:
-         return jjMoveStringLiteralDfa1_0(0x1001000000004L);
+         return jjMoveStringLiteralDfa1_0(0x1001000000004L, 0x0L);
       case 98:
-         return jjMoveStringLiteralDfa1_0(0x40000L);
+         return jjMoveStringLiteralDfa1_0(0x40000L, 0x0L);
       case 99:
-         return jjMoveStringLiteralDfa1_0(0x18030000000000L);
+         return jjMoveStringLiteralDfa1_0(0x18030000000000L, 0x0L);
       case 100:
-         return jjMoveStringLiteralDfa1_0(0x100000000000000L);
+         return jjMoveStringLiteralDfa1_0(0x1e00000000000000L, 0x4L);
       case 101:
-         return jjMoveStringLiteralDfa1_0(0x200000000000000L);
+         return jjMoveStringLiteralDfa1_0(0x0L, 0x8L);
+      case 104:
+         return jjMoveStringLiteralDfa1_0(0x2000000000000000L, 0x0L);
       case 105:
-         return jjMoveStringLiteralDfa1_0(0x8000L);
+         return jjMoveStringLiteralDfa1_0(0x8000L, 0x0L);
       case 108:
-         return jjMoveStringLiteralDfa1_0(0xd00000006000L);
+         return jjMoveStringLiteralDfa1_0(0xd00000006000L, 0x0L);
       case 109:
-         return jjMoveStringLiteralDfa1_0(0x4006000000000L);
+         return jjMoveStringLiteralDfa1_0(0x4084006000000000L, 0x0L);
       case 110:
-         return jjMoveStringLiteralDfa1_0(0x8L);
+         return jjMoveStringLiteralDfa1_0(0x8L, 0x0L);
       case 111:
-         return jjMoveStringLiteralDfa1_0(0x80000000000002L);
+         return jjMoveStringLiteralDfa1_0(0x2L, 0x2L);
       case 115:
-         return jjMoveStringLiteralDfa1_0(0x2048000000000L);
+         return jjMoveStringLiteralDfa1_0(0x8002048000000000L, 0x0L);
       case 116:
-         return jjMoveStringLiteralDfa1_0(0x80000000000L);
+         return jjMoveStringLiteralDfa1_0(0x80000000000L, 0x0L);
       case 117:
-         return jjMoveStringLiteralDfa1_0(0x200000000000L);
+         return jjMoveStringLiteralDfa1_0(0x200000000000L, 0x0L);
+      case 119:
+         return jjMoveStringLiteralDfa1_0(0x100000000000000L, 0x0L);
+      case 121:
+         return jjMoveStringLiteralDfa1_0(0x40000000000000L, 0x0L);
       case 124:
          return jjStopAtPos(0, 20);
       case 126:
@@ -403,11 +417,11 @@ private int jjMoveStringLiteralDfa0_0()
          return jjMoveNfa_0(3, 0);
    }
 }
-private int jjMoveStringLiteralDfa1_0(long active0)
+private int jjMoveStringLiteralDfa1_0(long active0, long active1)
 {
    try { curChar = input_stream.readChar(); }
    catch(java.io.IOException e) {
-      jjStopStringLiteralDfa_0(0, active0, 0L);
+      jjStopStringLiteralDfa_0(0, active0, active1);
       return 1;
    }
    switch(curChar)
@@ -433,83 +447,90 @@ private int jjMoveStringLiteralDfa1_0(long active0)
             return jjStopAtPos(1, 24);
          break;
       case 97:
-         return jjMoveStringLiteralDfa2_0(active0, 0x4000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x1e00004000000000L, active1, 0L);
       case 98:
-         return jjMoveStringLiteralDfa2_0(active0, 0x181000000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x1000000000000L, active1, 0x6L);
       case 101:
-         return jjMoveStringLiteralDfa2_0(active0, 0x400000040000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x8140400000040000L, active1, 0L);
       case 105:
-         return jjMoveStringLiteralDfa2_0(active0, 0x2000006000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x4000002000006000L, active1, 0L);
       case 110:
          if ((active0 & 0x8000L) != 0L)
             return jjStartNfaWithStates_0(1, 15, 74);
-         return jjMoveStringLiteralDfa2_0(active0, 0x200000000000004L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x4L, active1, 0x8L);
       case 111:
-         return jjMoveStringLiteralDfa2_0(active0, 0x4930000000008L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x2084930000000008L, active1, 0L);
       case 112:
-         return jjMoveStringLiteralDfa2_0(active0, 0x200000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x200000000000L, active1, 0L);
       case 113:
-         return jjMoveStringLiteralDfa2_0(active0, 0x2000000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x2000000000000L, active1, 0L);
       case 114:
          if ((active0 & 0x2L) != 0L)
             return jjStartNfaWithStates_0(1, 1, 74);
-         return jjMoveStringLiteralDfa2_0(active0, 0x80000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x80000000000L, active1, 0L);
       case 117:
-         return jjMoveStringLiteralDfa2_0(active0, 0x18048000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x18048000000000L, active1, 0L);
       case 118:
-         return jjMoveStringLiteralDfa2_0(active0, 0x1000000000L);
+         return jjMoveStringLiteralDfa2_0(active0, 0x1000000000L, active1, 0L);
       default :
          break;
    }
-   return jjStartNfa_0(0, active0, 0L);
+   return jjStartNfa_0(0, active0, active1);
 }
-private int jjMoveStringLiteralDfa2_0(long old0, long active0)
+private int jjMoveStringLiteralDfa2_0(long old0, long active0, long old1, long active1)
 {
-   if (((active0 &= old0)) == 0L)
-      return jjStartNfa_0(0, old0, 0L);
+   if (((active0 &= old0) | (active1 &= old1)) == 0L)
+      return jjStartNfa_0(0, old0, old1);
    try { curChar = input_stream.readChar(); }
    catch(java.io.IOException e) {
-      jjStopStringLiteralDfa_0(1, active0, 0L);
+      jjStopStringLiteralDfa_0(1, active0, active1);
       return 2;
    }
    switch(curChar)
    {
       case 58:
-         if ((active0 & 0x100000000000000L) != 0L)
-            return jjStopAtPos(2, 56);
+         if ((active1 & 0x4L) != 0L)
+            return jjStopAtPos(2, 66);
          break;
+      case 97:
+         return jjMoveStringLiteralDfa3_0(active0, 0x40000000000000L, active1, 0L);
       case 98:
-         return jjMoveStringLiteralDfa3_0(active0, 0x40000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x40000000000L, active1, 0L);
       case 99:
-         return jjMoveStringLiteralDfa3_0(active0, 0x800000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x8000800000000000L, active1, 0L);
       case 100:
          if ((active0 & 0x4L) != 0L)
             return jjStartNfaWithStates_0(2, 2, 74);
          else if ((active0 & 0x4000000000000L) != 0L)
             return jjStartNfaWithStates_0(2, 50, 74);
          break;
+      case 101:
+         return jjMoveStringLiteralDfa3_0(active0, 0x100000000000000L, active1, 0L);
       case 103:
          if ((active0 & 0x1000000000L) != 0L)
             return jjStartNfaWithStates_0(2, 36, 74);
          break;
       case 105:
-         return jjMoveStringLiteralDfa3_0(active0, 0x80000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x80000000000L, active1, 0L);
       case 106:
-         return jjMoveStringLiteralDfa3_0(active0, 0x80000000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0L, active1, 0x2L);
       case 107:
-         return jjMoveStringLiteralDfa3_0(active0, 0x6000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x6000L, active1, 0L);
       case 109:
          if ((active0 & 0x8000000000L) != 0L)
             return jjStartNfaWithStates_0(2, 39, 74);
          break;
       case 110:
          if ((active0 & 0x2000000000L) != 0L)
-            return jjStartNfaWithStates_0(2, 37, 74);
-         return jjMoveStringLiteralDfa3_0(active0, 0x420000000000L);
+         {
+            jjmatchedKind = 37;
+            jjmatchedPos = 2;
+         }
+         return jjMoveStringLiteralDfa3_0(active0, 0x4080420000000000L, active1, 0L);
       case 112:
-         return jjMoveStringLiteralDfa3_0(active0, 0x200000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x200000000000L, active1, 0L);
       case 114:
-         return jjMoveStringLiteralDfa3_0(active0, 0x1a000000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x1a000000000000L, active1, 0L);
       case 115:
          if ((active0 & 0x1000000000000L) != 0L)
             return jjStartNfaWithStates_0(2, 48, 74);
@@ -517,90 +538,119 @@ private int jjMoveStringLiteralDfa2_0(long old0, long active0)
       case 116:
          if ((active0 & 0x8L) != 0L)
             return jjStartNfaWithStates_0(2, 3, 74);
-         return jjMoveStringLiteralDfa3_0(active0, 0x40000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x40000L, active1, 0L);
       case 117:
-         return jjMoveStringLiteralDfa3_0(active0, 0x200010000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x2000010000000000L, active1, 0x8L);
       case 119:
-         return jjMoveStringLiteralDfa3_0(active0, 0x100000000000L);
+         return jjMoveStringLiteralDfa3_0(active0, 0x100000000000L, active1, 0L);
       case 120:
          if ((active0 & 0x4000000000L) != 0L)
             return jjStartNfaWithStates_0(2, 38, 74);
          break;
+      case 121:
+         if ((active0 & 0x400000000000000L) != 0L)
+         {
+            jjmatchedKind = 58;
+            jjmatchedPos = 2;
+         }
+         return jjMoveStringLiteralDfa3_0(active0, 0x1a00000000000000L, active1, 0L);
       default :
          break;
    }
-   return jjStartNfa_0(1, active0, 0L);
+   return jjStartNfa_0(1, active0, active1);
 }
-private int jjMoveStringLiteralDfa3_0(long old0, long active0)
+private int jjMoveStringLiteralDfa3_0(long old0, long active0, long old1, long active1)
 {
-   if (((active0 &= old0)) == 0L)
-      return jjStartNfa_0(1, old0, 0L);
+   if (((active0 &= old0) | (active1 &= old1)) == 0L)
+      return jjStartNfa_0(1, old0, old1);
    try { curChar = input_stream.readChar(); }
    catch(java.io.IOException e) {
-      jjStopStringLiteralDfa_0(2, active0, 0L);
+      jjStopStringLiteralDfa_0(2, active0, active1);
       return 3;
    }
    switch(curChar)
    {
       case 58:
-         if ((active0 & 0x80000000000000L) != 0L)
-            return jjStopAtPos(3, 55);
+         if ((active1 & 0x2L) != 0L)
+            return jjStopAtPos(3, 65);
          break;
+      case 79:
+         return jjMoveStringLiteralDfa4_0(active0, 0x1a00000000000000L, active1, 0L);
       case 97:
-         return jjMoveStringLiteralDfa4_0(active0, 0x800000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x800000000000L, active1, 0L);
       case 99:
-         return jjMoveStringLiteralDfa4_0(active0, 0x20000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x20000000000L, active1, 0L);
       case 101:
          if ((active0 & 0x2000L) != 0L)
          {
             jjmatchedKind = 13;
             jjmatchedPos = 3;
          }
-         return jjMoveStringLiteralDfa4_0(active0, 0x300000004000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x300000004000L, active1, 0L);
       case 103:
-         return jjMoveStringLiteralDfa4_0(active0, 0x400000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x400000000000L, active1, 0L);
+      case 107:
+         if ((active0 & 0x100000000000000L) != 0L)
+            return jjStartNfaWithStates_0(3, 56, 74);
+         break;
       case 109:
          if ((active0 & 0x80000000000L) != 0L)
             return jjStartNfaWithStates_0(3, 43, 74);
-         return jjMoveStringLiteralDfa4_0(active0, 0x200000000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0L, active1, 0x8L);
       case 110:
-         return jjMoveStringLiteralDfa4_0(active0, 0x10000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x10000000000L, active1, 0L);
+      case 111:
+         return jjMoveStringLiteralDfa4_0(active0, 0x8000000000000000L, active1, 0L);
       case 114:
-         return jjMoveStringLiteralDfa4_0(active0, 0x18000000000000L);
+         if ((active0 & 0x40000000000000L) != 0L)
+            return jjStartNfaWithStates_0(3, 54, 74);
+         else if ((active0 & 0x2000000000000000L) != 0L)
+            return jjStartNfaWithStates_0(3, 61, 74);
+         return jjMoveStringLiteralDfa4_0(active0, 0x18000000000000L, active1, 0L);
       case 115:
-         return jjMoveStringLiteralDfa4_0(active0, 0x40000000000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x40000000000L, active1, 0L);
       case 116:
          if ((active0 & 0x2000000000000L) != 0L)
             return jjStartNfaWithStates_0(3, 49, 74);
-         break;
+         return jjMoveStringLiteralDfa4_0(active0, 0x80000000000000L, active1, 0L);
+      case 117:
+         return jjMoveStringLiteralDfa4_0(active0, 0x4000000000000000L, active1, 0L);
       case 119:
-         return jjMoveStringLiteralDfa4_0(active0, 0x40000L);
+         return jjMoveStringLiteralDfa4_0(active0, 0x40000L, active1, 0L);
       default :
          break;
    }
-   return jjStartNfa_0(2, active0, 0L);
+   return jjStartNfa_0(2, active0, active1);
 }
-private int jjMoveStringLiteralDfa4_0(long old0, long active0)
+private int jjMoveStringLiteralDfa4_0(long old0, long active0, long old1, long active1)
 {
-   if (((active0 &= old0)) == 0L)
-      return jjStartNfa_0(2, old0, 0L);
+   if (((active0 &= old0) | (active1 &= old1)) == 0L)
+      return jjStartNfa_0(2, old0, old1);
    try { curChar = input_stream.readChar(); }
    catch(java.io.IOException e) {
-      jjStopStringLiteralDfa_0(3, active0, 0L);
+      jjStopStringLiteralDfa_0(3, active0, active1);
       return 4;
    }
    switch(curChar)
    {
       case 58:
-         if ((active0 & 0x200000000000000L) != 0L)
-            return jjStopAtPos(4, 57);
+         if ((active1 & 0x8L) != 0L)
+            return jjStopAtPos(4, 67);
          break;
       case 73:
-         return jjMoveStringLiteralDfa5_0(active0, 0x4000L);
+         return jjMoveStringLiteralDfa5_0(active0, 0x4000L, active1, 0L);
       case 97:
-         return jjMoveStringLiteralDfa5_0(active0, 0x20000000000L);
+         return jjMoveStringLiteralDfa5_0(active0, 0x20000000000L, active1, 0L);
       case 101:
-         return jjMoveStringLiteralDfa5_0(active0, 0x18000000040000L);
+         return jjMoveStringLiteralDfa5_0(active0, 0x18000000040000L, active1, 0L);
+      case 102:
+         return jjMoveStringLiteralDfa5_0(active0, 0x1a00000000000000L, active1, 0L);
+      case 104:
+         if ((active0 & 0x80000000000000L) != 0L)
+            return jjStartNfaWithStates_0(4, 55, 74);
+         break;
+      case 110:
+         return jjMoveStringLiteralDfa5_0(active0, 0x8000000000000000L, active1, 0L);
       case 114:
          if ((active0 & 0x100000000000L) != 0L)
             return jjStartNfaWithStates_0(4, 44, 74);
@@ -610,16 +660,16 @@ private int jjMoveStringLiteralDfa4_0(long old0, long active0)
       case 116:
          if ((active0 & 0x10000000000L) != 0L)
             return jjStartNfaWithStates_0(4, 40, 74);
-         return jjMoveStringLiteralDfa5_0(active0, 0xc40000000000L);
+         return jjMoveStringLiteralDfa5_0(active0, 0x4000c40000000000L, active1, 0L);
       default :
          break;
    }
-   return jjStartNfa_0(3, active0, 0L);
+   return jjStartNfa_0(3, active0, active1);
 }
-private int jjMoveStringLiteralDfa5_0(long old0, long active0)
+private int jjMoveStringLiteralDfa5_0(long old0, long active0, long old1, long active1)
 {
-   if (((active0 &= old0)) == 0L)
-      return jjStartNfa_0(3, old0, 0L);
+   if (((active0 &= old0) | (active1 &= old1)) == 0L)
+      return jjStartNfa_0(3, old0, old1);
    try { curChar = input_stream.readChar(); }
    catch(java.io.IOException e) {
       jjStopStringLiteralDfa_0(4, active0, 0L);
@@ -627,9 +677,21 @@ private int jjMoveStringLiteralDfa5_0(long old0, long active0)
    }
    switch(curChar)
    {
+      case 77:
+         return jjMoveStringLiteralDfa6_0(active0, 0x800000000000000L);
+      case 87:
+         return jjMoveStringLiteralDfa6_0(active0, 0x1000000000000000L);
+      case 89:
+         return jjMoveStringLiteralDfa6_0(active0, 0x200000000000000L);
+      case 100:
+         if ((active0 & 0x8000000000000000L) != 0L)
+            return jjStartNfaWithStates_0(5, 63, 74);
+         break;
       case 101:
          if ((active0 & 0x800000000000L) != 0L)
             return jjStartNfaWithStates_0(5, 47, 74);
+         else if ((active0 & 0x4000000000000000L) != 0L)
+            return jjStartNfaWithStates_0(5, 62, 74);
          return jjMoveStringLiteralDfa6_0(active0, 0x40000L);
       case 103:
          return jjMoveStringLiteralDfa6_0(active0, 0x4000L);
@@ -661,12 +723,16 @@ private int jjMoveStringLiteralDfa6_0(long old0, long active0)
    }
    switch(curChar)
    {
+      case 101:
+         return jjMoveStringLiteralDfa7_0(active0, 0x1200000000000000L);
       case 105:
          return jjMoveStringLiteralDfa7_0(active0, 0x40000000000L);
       case 110:
          if ((active0 & 0x40000L) != 0L)
             return jjStartNfaWithStates_0(6, 18, 74);
          return jjMoveStringLiteralDfa7_0(active0, 0x4000L);
+      case 111:
+         return jjMoveStringLiteralDfa7_0(active0, 0x800000000000000L);
       case 116:
          return jjMoveStringLiteralDfa7_0(active0, 0x18000000000000L);
       default :
@@ -689,8 +755,12 @@ private int jjMoveStringLiteralDfa7_0(long old0, long active0)
          return jjMoveStringLiteralDfa8_0(active0, 0x8000000000000L);
       case 84:
          return jjMoveStringLiteralDfa8_0(active0, 0x10000000000000L);
+      case 97:
+         return jjMoveStringLiteralDfa8_0(active0, 0x200000000000000L);
+      case 101:
+         return jjMoveStringLiteralDfa8_0(active0, 0x1000000000000000L);
       case 110:
-         return jjMoveStringLiteralDfa8_0(active0, 0x40000000000L);
+         return jjMoveStringLiteralDfa8_0(active0, 0x800040000000000L);
       case 111:
          return jjMoveStringLiteralDfa8_0(active0, 0x4000L);
       default :
@@ -717,8 +787,16 @@ private int jjMoveStringLiteralDfa8_0(long old0, long active0)
          break;
       case 105:
          return jjMoveStringLiteralDfa9_0(active0, 0x10000000000000L);
+      case 107:
+         if ((active0 & 0x1000000000000000L) != 0L)
+            return jjStartNfaWithStates_0(8, 60, 74);
+         break;
       case 114:
+         if ((active0 & 0x200000000000000L) != 0L)
+            return jjStartNfaWithStates_0(8, 57, 74);
          return jjMoveStringLiteralDfa9_0(active0, 0x4000L);
+      case 116:
+         return jjMoveStringLiteralDfa9_0(active0, 0x800000000000000L);
       default :
          break;
    }
@@ -737,6 +815,10 @@ private int jjMoveStringLiteralDfa9_0(long old0, long active0)
    {
       case 101:
          return jjMoveStringLiteralDfa10_0(active0, 0x4000L);
+      case 104:
+         if ((active0 & 0x800000000000000L) != 0L)
+            return jjStartNfaWithStates_0(9, 59, 74);
+         break;
       case 109:
          return jjMoveStringLiteralDfa10_0(active0, 0x10000000000000L);
       case 116:
@@ -855,324 +937,324 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 26:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 32:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 63:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 5:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 64:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 30:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 29:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 35:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 27:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 33:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 6:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 74:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
@@ -1183,137 +1265,137 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjCheckNAdd(42);
                   if ((0x3fe000000000000L & l) != 0L)
                   {
-                     if (kind > 71)
-                        kind = 71;
+                     if (kind > 81)
+                        kind = 81;
                      jjCheckNAddTwoStates(39, 40);
                   }
                   else if (curChar == 48)
                   {
-                     if (kind > 71)
-                        kind = 71;
+                     if (kind > 81)
+                        kind = 81;
                      jjCheckNAddStates(9, 11);
                   }
                   break;
                case 31:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 36:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 28:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 34:
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                   }
                   else if (curChar == 46)
                      jjstateSet[jjnewStateCnt++] = 70;
                   if ((0x3ff000000000000L & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   else if (curChar == 43)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAdd(69);
                   }
                   break;
                case 38:
                   if ((0x3fe000000000000L & l) == 0L)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddTwoStates(39, 40);
                   break;
                case 39:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddTwoStates(39, 40);
                   break;
                case 41:
@@ -1323,8 +1405,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 42:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 72)
-                     kind = 72;
+                  if (kind > 82)
+                     kind = 82;
                   jjCheckNAddStates(12, 14);
                   break;
                case 44:
@@ -1334,8 +1416,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 45:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 72)
-                     kind = 72;
+                  if (kind > 82)
+                     kind = 82;
                   jjCheckNAddTwoStates(45, 46);
                   break;
                case 47:
@@ -1349,15 +1431,15 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 49:
                   if (curChar != 46)
                      break;
-                  if (kind > 72)
-                     kind = 72;
+                  if (kind > 82)
+                     kind = 82;
                   jjCheckNAddStates(15, 17);
                   break;
                case 50:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 72)
-                     kind = 72;
+                  if (kind > 82)
+                     kind = 82;
                   jjCheckNAddStates(15, 17);
                   break;
                case 51:
@@ -1371,8 +1453,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 54:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 72)
-                     kind = 72;
+                  if (kind > 82)
+                     kind = 82;
                   jjCheckNAddTwoStates(54, 46);
                   break;
                case 55:
@@ -1382,36 +1464,36 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 56:
                   if (curChar != 48)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddStates(9, 11);
                   break;
                case 57:
                   if ((0xff000000000000L & l) == 0L)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddTwoStates(57, 40);
                   break;
                case 59:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddTwoStates(59, 40);
                   break;
                case 67:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAddStates(0, 2);
                   break;
                case 68:
                   if (curChar != 43)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAdd(69);
                   break;
                case 69:
@@ -1421,20 +1503,20 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 71:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAddStates(18, 20);
                   break;
                case 72:
                   if ((0x3ff000000000000L & l) == 0L)
                      break;
-                  if (kind > 60)
-                     kind = 60;
+                  if (kind > 70)
+                     kind = 70;
                   jjCheckNAddTwoStates(72, 73);
                   break;
                case 73:
-                  if (curChar == 43 && kind > 60)
-                     kind = 60;
+                  if (curChar == 43 && kind > 70)
+                     kind = 70;
                   break;
                default : break;
             }
@@ -1450,14 +1532,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 26:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 115)
@@ -1466,14 +1548,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 32:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 110)
@@ -1482,14 +1564,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 63:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 111)
@@ -1500,14 +1582,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 5:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 117)
@@ -1516,14 +1598,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 64:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 119)
@@ -1535,14 +1617,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 30:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 84)
@@ -1551,14 +1633,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 29:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 105)
@@ -1567,14 +1649,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 35:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 114)
@@ -1583,14 +1665,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 27:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 101)
@@ -1599,14 +1681,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 33:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 101)
@@ -1615,14 +1697,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 6:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 114)
@@ -1631,22 +1713,22 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 74:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   break;
                case 3:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(21, 25);
                   }
                   if (curChar == 110)
@@ -1667,14 +1749,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 31:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 116)
@@ -1683,14 +1765,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 36:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 117)
@@ -1699,14 +1781,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 28:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 109)
@@ -1715,14 +1797,14 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 34:
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 60)
-                        kind = 60;
+                     if (kind > 70)
+                        kind = 70;
                      jjCheckNAddTwoStates(72, 73);
                   }
                   if ((0x7fffffe87fffffeL & l) != 0L)
                   {
-                     if (kind > 59)
-                        kind = 59;
+                     if (kind > 69)
+                        kind = 69;
                      jjCheckNAddStates(0, 2);
                   }
                   if (curChar == 114)
@@ -1825,16 +1907,16 @@ private int jjMoveNfa_0(int startState, int curPos)
                      jjstateSet[jjnewStateCnt++] = 36;
                   break;
                case 40:
-                  if ((0x110000001100L & l) != 0L && kind > 71)
-                     kind = 71;
+                  if ((0x110000001100L & l) != 0L && kind > 81)
+                     kind = 81;
                   break;
                case 43:
                   if ((0x2000000020L & l) != 0L)
                      jjAddStates(28, 29);
                   break;
                case 46:
-                  if ((0x5400000054L & l) != 0L && kind > 72)
-                     kind = 72;
+                  if ((0x5400000054L & l) != 0L && kind > 82)
+                     kind = 82;
                   break;
                case 52:
                   if ((0x2000000020L & l) != 0L)
@@ -1847,8 +1929,8 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 59:
                   if ((0x7e0000007eL & l) == 0L)
                      break;
-                  if (kind > 71)
-                     kind = 71;
+                  if (kind > 81)
+                     kind = 81;
                   jjCheckNAddTwoStates(59, 40);
                   break;
                case 60:
@@ -1870,30 +1952,30 @@ private int jjMoveNfa_0(int startState, int curPos)
                case 66:
                   if ((0x7fffffe87fffffeL & l) == 0L)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAddStates(21, 25);
                   break;
                case 67:
                   if ((0x7fffffe87fffffeL & l) == 0L)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAddStates(0, 2);
                   break;
                case 70:
                case 71:
                   if ((0x7fffffe87fffffeL & l) == 0L)
                      break;
-                  if (kind > 59)
-                     kind = 59;
+                  if (kind > 69)
+                     kind = 69;
                   jjCheckNAddStates(18, 20);
                   break;
                case 72:
                   if ((0x7fffffe87fffffeL & l) == 0L)
                      break;
-                  if (kind > 60)
-                     kind = 60;
+                  if (kind > 70)
+                     kind = 70;
                   jjCheckNAddTwoStates(72, 73);
                   break;
                default : break;
@@ -1945,7 +2027,7 @@ private int jjMoveStringLiteralDfa0_1()
    switch(curChar)
    {
       case 39:
-         return jjStopAtPos(0, 67);
+         return jjStopAtPos(0, 77);
       default :
          return jjMoveNfa_1(0, 0);
    }
@@ -1975,12 +2057,12 @@ private int jjMoveNfa_1(int startState, int curPos)
             switch(jjstateSet[--i])
             {
                case 0:
-                  if ((0xffffff7fffffffffL & l) != 0L && kind > 66)
-                     kind = 66;
+                  if ((0xffffff7fffffffffL & l) != 0L && kind > 76)
+                     kind = 76;
                   break;
                case 1:
-                  if ((0x8400000000L & l) != 0L && kind > 65)
-                     kind = 65;
+                  if ((0x8400000000L & l) != 0L && kind > 75)
+                     kind = 75;
                   break;
                case 2:
                   if ((0xf000000000000L & l) != 0L)
@@ -1989,13 +2071,13 @@ private int jjMoveNfa_1(int startState, int curPos)
                case 3:
                   if ((0xff000000000000L & l) == 0L)
                      break;
-                  if (kind > 65)
-                     kind = 65;
+                  if (kind > 75)
+                     kind = 75;
                   jjstateSet[jjnewStateCnt++] = 4;
                   break;
                case 4:
-                  if ((0xff000000000000L & l) != 0L && kind > 65)
-                     kind = 65;
+                  if ((0xff000000000000L & l) != 0L && kind > 75)
+                     kind = 75;
                   break;
                default : break;
             }
@@ -2011,19 +2093,19 @@ private int jjMoveNfa_1(int startState, int curPos)
                case 0:
                   if ((0xffffffffefffffffL & l) != 0L)
                   {
-                     if (kind > 66)
-                        kind = 66;
+                     if (kind > 76)
+                        kind = 76;
                   }
                   else if (curChar == 92)
                      jjAddStates(32, 34);
                   break;
                case 1:
-                  if ((0x14404510000000L & l) != 0L && kind > 65)
-                     kind = 65;
+                  if ((0x14404510000000L & l) != 0L && kind > 75)
+                     kind = 75;
                   break;
                case 5:
-                  if ((0xffffffffefffffffL & l) != 0L && kind > 66)
-                     kind = 66;
+                  if ((0xffffffffefffffffL & l) != 0L && kind > 76)
+                     kind = 76;
                   break;
                default : break;
             }
@@ -2041,8 +2123,8 @@ private int jjMoveNfa_1(int startState, int curPos)
             switch(jjstateSet[--i])
             {
                case 0:
-                  if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 66)
-                     kind = 66;
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 76)
+                     kind = 76;
                   break;
                default : break;
             }
@@ -2078,7 +2160,7 @@ private int jjMoveStringLiteralDfa0_2()
    switch(curChar)
    {
       case 34:
-         return jjStopAtPos(0, 70);
+         return jjStopAtPos(0, 80);
       default :
          return jjMoveNfa_2(0, 0);
    }
@@ -2102,12 +2184,12 @@ private int jjMoveNfa_2(int startState, int curPos)
             switch(jjstateSet[--i])
             {
                case 0:
-                  if ((0xfffffffbffffffffL & l) != 0L && kind > 69)
-                     kind = 69;
+                  if ((0xfffffffbffffffffL & l) != 0L && kind > 79)
+                     kind = 79;
                   break;
                case 1:
-                  if ((0x8400000000L & l) != 0L && kind > 68)
-                     kind = 68;
+                  if ((0x8400000000L & l) != 0L && kind > 78)
+                     kind = 78;
                   break;
                case 2:
                   if ((0xf000000000000L & l) != 0L)
@@ -2116,13 +2198,13 @@ private int jjMoveNfa_2(int startState, int curPos)
                case 3:
                   if ((0xff000000000000L & l) == 0L)
                      break;
-                  if (kind > 68)
-                     kind = 68;
+                  if (kind > 78)
+                     kind = 78;
                   jjstateSet[jjnewStateCnt++] = 4;
                   break;
                case 4:
-                  if ((0xff000000000000L & l) != 0L && kind > 68)
-                     kind = 68;
+                  if ((0xff000000000000L & l) != 0L && kind > 78)
+                     kind = 78;
                   break;
                default : break;
             }
@@ -2138,19 +2220,19 @@ private int jjMoveNfa_2(int startState, int curPos)
                case 0:
                   if ((0xffffffffefffffffL & l) != 0L)
                   {
-                     if (kind > 69)
-                        kind = 69;
+                     if (kind > 79)
+                        kind = 79;
                   }
                   else if (curChar == 92)
                      jjAddStates(32, 34);
                   break;
                case 1:
-                  if ((0x14404510000000L & l) != 0L && kind > 68)
-                     kind = 68;
+                  if ((0x14404510000000L & l) != 0L && kind > 78)
+                     kind = 78;
                   break;
                case 5:
-                  if ((0xffffffffefffffffL & l) != 0L && kind > 69)
-                     kind = 69;
+                  if ((0xffffffffefffffffL & l) != 0L && kind > 79)
+                     kind = 79;
                   break;
                default : break;
             }
@@ -2168,8 +2250,8 @@ private int jjMoveNfa_2(int startState, int curPos)
             switch(jjstateSet[--i])
             {
                case 0:
-                  if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 69)
-                     kind = 69;
+                  if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 79)
+                     kind = 79;
                   break;
                default : break;
             }
@@ -2216,9 +2298,12 @@ null, null, null, "\141\166\147", "\155\151\156", "\155\141\170", "\163\165\155"
 "\143\157\165\156\164", "\143\157\156\143\141\164", "\163\165\142\163\164\162\151\156\147", 
 "\164\162\151\155", "\154\157\167\145\162", "\165\160\160\145\162", "\154\145\156\147\164\150", 
 "\154\157\143\141\164\145", "\141\142\163", "\163\161\162\164", "\155\157\144", 
-"\143\165\162\162\145\156\164\104\141\164\145", "\143\165\162\162\145\156\164\124\151\155\145", null, "\44", 
-"\157\142\152\72", "\144\142\72", "\145\156\165\155\72", "\52", null, null, null, null, null, 
-null, null, null, null, null, null, null, null, null, null, null, null, null, };
+"\143\165\162\162\145\156\164\104\141\164\145", "\143\165\162\162\145\156\164\124\151\155\145", null, "\171\145\141\162", 
+"\155\157\156\164\150", "\167\145\145\153", "\144\141\171\117\146\131\145\141\162", "\144\141\171", 
+"\144\141\171\117\146\115\157\156\164\150", "\144\141\171\117\146\127\145\145\153", "\150\157\165\162", 
+"\155\151\156\165\164\145", "\163\145\143\157\156\144", "\44", "\157\142\152\72", "\144\142\72", 
+"\145\156\165\155\72", "\52", null, null, null, null, null, null, null, null, null, null, null, null, 
+null, null, null, null, null, null, };
 
 /** Lexer state names. */
 public static final String[] lexStateNames = {
@@ -2231,17 +2316,17 @@ public static final String[] lexStateNames = {
 public static final int[] jjnewLexState = {
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
    -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 
-   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, -1, -1, 0, -1, -1, 0, -1, -1, -1, -1, 
-   -1, -1, 
+   -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 
+   -1, -1, 0, -1, -1, 0, -1, -1, -1, -1, -1, -1, 
 };
 static final long[] jjtoToken = {
-   0x1ffffffe1fffffffL, 0x1c8L, 
+   0xfffffffe1fffffffL, 0x7207fL, 
 };
 static final long[] jjtoSkip = {
    0x1e0000000L, 0x0L, 
 };
 static final long[] jjtoMore = {
-   0x8000000000000000L, 0x37L, 
+   0x0L, 0xde00L, 
 };
 protected JavaCharStream input_stream;
 private final int[] jjrounds = new int[74];
@@ -2433,32 +2518,32 @@ void MoreLexicalActions()
    jjimageLen += (lengthOfMatch = jjmatchedPos + 1);
    switch(jjmatchedKind)
    {
-      case 63 :
+      case 73 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
            stringBuffer = new StringBuffer();
          break;
-      case 64 :
+      case 74 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
             stringBuffer = new StringBuffer();
          break;
-      case 65 :
+      case 75 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
           stringBuffer.append( escapeChar() );
          break;
-      case 66 :
+      case 76 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
           stringBuffer.append( image.charAt(image.length()-1) );
          break;
-      case 68 :
+      case 78 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
           stringBuffer.append( escapeChar() );
          break;
-      case 69 :
+      case 79 :
          image.append(input_stream.GetSuffix(jjimageLen));
          jjimageLen = 0;
           stringBuffer.append( image.charAt(image.length()-1) );
@@ -2471,19 +2556,19 @@ void TokenLexicalActions(Token matchedToken)
 {
    switch(jjmatchedKind)
    {
-      case 67 :
+      case 77 :
         image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
           literalValue = stringBuffer.toString();
          break;
-      case 70 :
+      case 80 :
         image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
           literalValue = stringBuffer.toString();
          break;
-      case 71 :
+      case 81 :
         image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
           literalValue = makeInt();
          break;
-      case 72 :
+      case 82 :
         image.append(input_stream.GetSuffix(jjimageLen + (lengthOfMatch = jjmatchedPos + 1)));
           literalValue = makeFloat();
          break;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
index b03d25e..2b8c022 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserTreeConstants.java
@@ -74,9 +74,10 @@ public interface ExpressionParserTreeConstants
   public int JJTCURRENTDATE = 49;
   public int JJTCURRENTTIME = 50;
   public int JJTCURRENTTIMESTAMP = 51;
-  public int JJTNAMEDPARAMETER = 52;
-  public int JJTOBJPATH = 53;
-  public int JJTDBPATH = 54;
+  public int JJTEXTRACT = 52;
+  public int JJTNAMEDPARAMETER = 53;
+  public int JJTOBJPATH = 54;
+  public int JJTDBPATH = 55;
 
 
   public String[] jjtNodeName = {
@@ -132,9 +133,10 @@ public interface ExpressionParserTreeConstants
     "CurrentDate",
     "CurrentTime",
     "CurrentTimestamp",
+    "Extract",
     "NamedParameter",
     "ObjPath",
     "DbPath",
   };
 }
-/* JavaCC - OriginalChecksum=7571de31b81c878cf4b5f52ebb555fb1 (do not edit this line) */
+/* JavaCC - OriginalChecksum=fa5ebea216f594b98b337cf22871715e (do not edit this line) */

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
index f61c692..2bca76d 100644
--- a/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
+++ b/cayenne-server/src/main/jjtree/org/apache/cayenne/exp/parser/ExpressionParser.jjt
@@ -179,13 +179,13 @@ void scalarConstExpression() : {}
 	| 
 	  namedParameter()
 	| 
-	  <INT_LITERAL> { jjtThis.setValue(token_source.literalValue); } #Scalar(0)
+	  <INT_LITERAL>   { jjtThis.setValue(token_source.literalValue); } #Scalar(0)
 	| 
-	   <FLOAT_LITERAL>{ jjtThis.setValue(token_source.literalValue); }  #Scalar(0)
+	  <FLOAT_LITERAL> { jjtThis.setValue(token_source.literalValue); } #Scalar(0)
 	|
-	  <TRUE> { jjtThis.setValue(true); }  #Scalar(0)
+	  <TRUE>  { jjtThis.setValue(true);  } #Scalar(0)
 	| 
-	  <FALSE> { jjtThis.setValue(false); }  #Scalar(0)
+	  <FALSE> { jjtThis.setValue(false); } #Scalar(0)
 }
 
 void numericExpression() : {}
@@ -314,7 +314,7 @@ void upper() #Upper : { }
 
 void functionsReturningNumerics() : { }
 {
-	length() | locate() | abs() | sqrt() | mod()
+	length() | locate() | abs() | sqrt() | mod() | dateTimeExtractingFunction()
 }
 
 void length() #Length : { }
@@ -397,6 +397,27 @@ void currentTimestamp() #CurrentTimestamp : {}
     <CURRENT_TIMESTAMP> "(" ")"
 }
 
+/* Date/time parts extracting function */
+void dateTimeExtractingFunction() #Extract(1) : {
+    Token t;
+}
+{
+    (
+        t = <YEAR>
+        | t = <MONTH>
+        | t = <WEEK>
+        | t = <DAY_OF_YEAR>
+        | t = <DAY>
+        | t = <DAY_OF_MONTH>
+        | t = <DAY_OF_WEEK>
+        | t = <HOUR>
+        | t = <MINUTE>
+        | t = <SECOND>
+    ) {
+        jjtThis.setPartToken(t.image);
+    }
+    "(" pathExpression() ")"
+}
 
 TOKEN_MGR_DECLS:
 {
@@ -521,6 +542,24 @@ TOKEN : /* functions returning datetime */
 	|	<CURRENT_TIMESTAMP: "currentTimestamp" | "now" >
 }
 
+/*
+    Data/time parts extracting functions' names.
+    MUST be in sync with enum ASTExtract.DateTimePart.
+*/
+TOKEN :
+{
+    <YEAR: "year">
+    | <MONTH: "month">
+    | <WEEK: "week">
+    | <DAY_OF_YEAR: "dayOfYear">
+    | <DAY: "day">
+    | <DAY_OF_MONTH: "dayOfMonth">
+    | <DAY_OF_WEEK: "dayOfWeek">
+    | <HOUR: "hour">
+    | <MINUTE: "minute">
+    | <SECOND: "second">
+}
+
 void namedParameter() :
 {
 	Token t;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentDateTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentDateTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentDateTest.java
new file mode 100644
index 0000000..f3bb0aa
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentDateTest.java
@@ -0,0 +1,51 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.util.Date;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @since 4.0
+ */
+public class ASTCurrentDateTest {
+
+    @Test
+    public void testParse() {
+        Expression exp2 = ExpressionFactory.exp("currentDate()");
+        assertTrue(exp2 instanceof ASTCurrentDate);
+
+        assertEquals("currentDate()", exp2.toString());
+    }
+
+    @Test
+    public void testEvaluate() {
+        Expression exp = new ASTCurrentDate();
+        Object result = exp.evaluate(new Object());
+        assertTrue(result instanceof Date);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimeTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimeTest.java b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimeTest.java
new file mode 100644
index 0000000..d79b65d
--- /dev/null
+++ b/cayenne-server/src/test/java/org/apache/cayenne/exp/parser/ASTCurrentTimeTest.java
@@ -0,0 +1,50 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.util.Date;
+
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @since 4.0
+ */
+public class ASTCurrentTimeTest {
+
+    @Test
+    public void testParse() {
+        Expression exp2 = ExpressionFactory.exp("currentTime()");
+        assertTrue(exp2 instanceof ASTCurrentTime);
+
+        assertEquals("currentTime()", exp2.toString());
+    }
+
+    @Test
+    public void testEvaluate() {
+        Expression exp = new ASTCurrentTime();
+        Object result = exp.evaluate(new Object());
+        assertTrue(result instanceof Date);
+    }
+}


[3/3] cayenne git commit: CAY-2269 Add support for date/time components extraction in expression functions

Posted by nt...@apache.org.
CAY-2269 Add support for date/time components extraction in expression functions


Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/05a77250
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/05a77250
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/05a77250

Branch: refs/heads/master
Commit: 05a77250221c23aede7267835fb55d997560c5b0
Parents: e56a93f
Author: Nikita Timofeev <st...@gmail.com>
Authored: Mon Mar 20 13:00:23 2017 +0300
Committer: Nikita Timofeev <st...@gmail.com>
Committed: Mon Mar 20 13:00:23 2017 +0300

----------------------------------------------------------------------
 .../translator/select/QualifierTranslator.java  |  15 +-
 .../cayenne/dba/db2/DB2QualifierTranslator.java |  20 +
 .../dba/derby/DerbyQualifierTranslator.java     |  17 +
 .../firebird/FirebirdQualifierTranslator.java   |  36 +
 .../frontbase/FrontBaseQualifierTranslator.java |  34 +
 .../dba/hsqldb/HSQLQualifierTranslator.java     |  15 +
 .../dba/ingres/IngresQualifierTranslator.java   |  15 +
 .../dba/mysql/MySQLQualifierTranslator.java     |  15 +
 .../openbase/OpenBaseQualifierTranslator.java   |  15 +
 .../dba/oracle/OracleQualifierTranslator.java   |  47 +
 .../postgres/PostgresQualifierTranslator.java   |  37 +
 .../cayenne/dba/sqlite/SQLiteAdapter.java       |   4 +-
 .../cayenne/dba/sqlite/SQLiteDateType.java      |  70 +-
 .../dba/sqlite/SQLiteQualifierTranslator.java   |  60 ++
 .../SQLServerTrimmingQualifierTranslator.java   |  35 +
 .../dba/sybase/SybaseQualifierTranslator.java   |  36 +
 .../cayenne/exp/FunctionExpressionFactory.java  | 155 +++
 .../cayenne/exp/parser/ASTCurrentDate.java      |   5 -
 .../cayenne/exp/parser/ASTCurrentTime.java      |   5 -
 .../cayenne/exp/parser/ASTCurrentTimestamp.java |   5 -
 .../apache/cayenne/exp/parser/ASTExtract.java   | 125 +++
 .../cayenne/exp/parser/ASTFunctionCall.java     |  24 +-
 .../cayenne/exp/parser/ExpressionParser.java    | 302 ++++--
 .../exp/parser/ExpressionParserConstants.java   |  64 +-
 .../parser/ExpressionParserTokenManager.java    | 979 ++++++++++---------
 .../parser/ExpressionParserTreeConstants.java   |  10 +-
 .../cayenne/exp/parser/ExpressionParser.jjt     |  49 +-
 .../cayenne/exp/parser/ASTCurrentDateTest.java  |  51 +
 .../cayenne/exp/parser/ASTCurrentTimeTest.java  |  50 +
 .../exp/parser/ASTCurrentTimestampTest.java     |  54 +
 .../apache/cayenne/exp/parser/ASTExtractIT.java | 240 +++++
 .../cayenne/exp/parser/ASTExtractTest.java      | 162 +++
 .../apache/cayenne/unit/DerbyUnitDbAdapter.java |  12 +
 .../cayenne/unit/FrontBaseUnitDbAdapter.java    |  11 +
 .../org/apache/cayenne/unit/UnitDbAdapter.java  |   5 +
 .../ServerCaseDataSourceInfoProvider.java       |   2 +-
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   1 +
 37 files changed, 2161 insertions(+), 621 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
index aad7eca..deb7d52 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/access/translator/select/QualifierTranslator.java
@@ -30,6 +30,7 @@ import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.TraversalHandler;
 import org.apache.cayenne.exp.parser.ASTDbPath;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.ASTObjPath;
 import org.apache.cayenne.exp.parser.PatternMatchNode;
@@ -413,7 +414,11 @@ public class QualifierTranslator extends QueryAssemblerHelper implements Travers
 		boolean parenthesisNeeded = parenthesisNeeded(node, parentNode);
 
 		if(node.getType() == Expression.FUNCTION_CALL) {
-			appendFunction((ASTFunctionCall)node);
+			if(node instanceof ASTExtract) {
+				appendExtractFunction((ASTExtract) node);
+			} else {
+				appendFunction((ASTFunctionCall) node);
+			}
 			if(parenthesisNeeded) {
 				out.append("(");
 			}
@@ -623,6 +628,14 @@ public class QualifierTranslator extends QueryAssemblerHelper implements Travers
 	}
 
 	/**
+	 * Special case for extract date/time parts functions as they have many variants
+	 * @since 4.0
+	 */
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		appendFunction(functionExpression);
+	}
+
+	/**
 	 * Append scalar argument of a function call
 	 * Used only for values stored in ASTScalar other
 	 * expressions appended in objectNode() method

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2QualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2QualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2QualifierTranslator.java
index 09b369a..6a60233 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2QualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/db2/DB2QualifierTranslator.java
@@ -28,6 +28,7 @@ import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.dba.TypesMapping;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.parser.ASTEqual;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.ASTNotEqual;
 import org.apache.cayenne.exp.parser.SimpleNode;
@@ -151,4 +152,23 @@ public class DB2QualifierTranslator extends TrimmingQualifierTranslator {
 			super.clearLastFunctionArgDivider(functionExpression);
 		}
 	}
+
+	/**
+	 * @since 4.0
+	 */
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		switch (functionExpression.getPart()) {
+			case DAY_OF_MONTH:
+				out.append("DAY");
+				break;
+			case DAY_OF_WEEK:
+			case DAY_OF_YEAR:
+				// db2 variants are without '_'
+				out.append(functionExpression.getPart().name().replace("_", ""));
+				break;
+			default:
+				appendFunction(functionExpression);
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyQualifierTranslator.java
index 84c5889..2767417 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/derby/DerbyQualifierTranslator.java
@@ -21,10 +21,12 @@ package org.apache.cayenne.dba.derby;
 import java.io.IOException;
 import java.sql.Types;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
 import org.apache.cayenne.exp.parser.ASTEqual;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.ASTNotEqual;
 import org.apache.cayenne.exp.parser.SimpleNode;
@@ -120,4 +122,19 @@ public class DerbyQualifierTranslator extends TrimmingQualifierTranslator {
 			super.clearLastFunctionArgDivider(functionExpression);
 		}
 	}
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		switch (functionExpression.getPart()) {
+			case DAY_OF_MONTH:
+				out.append("DAY");
+				break;
+			case DAY_OF_WEEK:
+			case DAY_OF_YEAR:
+			case WEEK:
+				throw new CayenneRuntimeException("Function " + functionExpression.getPartCamelCaseName() + "() is unsupported in Derby.");
+			default:
+				super.appendExtractFunction(functionExpression);
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdQualifierTranslator.java
index 503358f..eae42f7 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/firebird/FirebirdQualifierTranslator.java
@@ -23,6 +23,7 @@ import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.dba.oracle.OracleQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 
 import java.io.IOException;
@@ -141,5 +142,40 @@ public class FirebirdQualifierTranslator extends QualifierTranslator {
 			default:
 				super.clearLastFunctionArgDivider(functionExpression);
 		}
+		if(functionExpression instanceof ASTExtract) {
+			out.append(")");
+		}
+	}
+
+	@Override
+	protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+		if (node.getType() == Expression.FUNCTION_CALL) {
+			if (node instanceof ASTExtract) {
+				return false;
+			}
+		}
+
+		return super.parenthesisNeeded(node, parentNode);
+	}
+
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		out.append("EXTRACT(");
+		switch (functionExpression.getPart()) {
+			case DAY_OF_MONTH:
+				out.append("DAY");
+				break;
+			case DAY_OF_WEEK:
+				out.append("WEEKDAY");
+				break;
+			case DAY_OF_YEAR:
+				out.append("YEARDAY");
+				break;
+			default:
+				out.append(functionExpression.getPartCamelCaseName());
+		}
+
+		out.append(" FROM ");
 	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java
index 615bf68..8315a4c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/frontbase/FrontBaseQualifierTranslator.java
@@ -19,8 +19,11 @@
 
 package org.apache.cayenne.dba.frontbase;
 
+import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 
 /**
@@ -96,5 +99,36 @@ public class FrontBaseQualifierTranslator extends QualifierTranslator {
             default:
                 super.clearLastFunctionArgDivider(functionExpression);
         }
+        if(functionExpression instanceof ASTExtract) {
+            out.append(")");
+        }
+    }
+
+    @Override
+    protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+        if (node.getType() == Expression.FUNCTION_CALL) {
+            if (node instanceof ASTExtract) {
+                return false;
+            }
+        }
+
+        return super.parenthesisNeeded(node, parentNode);
+    }
+
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        out.append("EXTRACT(");
+        switch (functionExpression.getPart()) {
+            case DAY_OF_WEEK:
+            case DAY_OF_YEAR:
+            case WEEK:
+                throw new CayenneRuntimeException("Function " + functionExpression.getPartCamelCaseName() + "() is unsupported in FrontBase.");
+            case DAY_OF_MONTH:
+                out.append("DAY");
+                break;
+            default:
+                out.append(functionExpression.getPart().name());
+        }
+        out.append(" FROM ");
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java
index bc3990d..513a707 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/hsqldb/HSQLQualifierTranslator.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.PatternMatchNode;
 
@@ -69,4 +70,18 @@ public class HSQLQualifierTranslator extends TrimmingQualifierTranslator {
             super.appendFunction(functionExpression);
         }
     }
+
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        switch (functionExpression.getPart()) {
+            case DAY_OF_WEEK:
+            case DAY_OF_MONTH:
+            case DAY_OF_YEAR:
+                // hsqldb variants are without '_'
+                out.append(functionExpression.getPart().name().replace("_", ""));
+                break;
+            default:
+                appendFunction(functionExpression);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java
index 222fe96..8334ff4 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/ingres/IngresQualifierTranslator.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.Node;
 
@@ -98,6 +99,20 @@ class IngresQualifierTranslator extends TrimmingQualifierTranslator {
         }
     }
 
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        switch (functionExpression.getPart()) {
+            case DAY_OF_WEEK:
+            case DAY_OF_MONTH:
+            case DAY_OF_YEAR:
+                // ingres variants are without '_'
+                out.append(functionExpression.getPart().name().replace("_", ""));
+                break;
+            default:
+                appendFunction(functionExpression);
+        }
+    }
+
     private void swapNodeChildren(Node node, int i, int j) {
         Node ni = node.jjtGetChild(i);
         Node nj = node.jjtGetChild(j);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
index 77f4dde..ac520e2 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/mysql/MySQLQualifierTranslator.java
@@ -24,6 +24,7 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.PatternMatchNode;
 
 class MySQLQualifierTranslator extends QualifierTranslator {
@@ -88,4 +89,18 @@ class MySQLQualifierTranslator extends QualifierTranslator {
             }
         }
     }
+
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        switch (functionExpression.getPart()) {
+            case DAY_OF_WEEK:
+            case DAY_OF_MONTH:
+            case DAY_OF_YEAR:
+                // mysql variants are without '_'
+                out.append(functionExpression.getPart().name().replace("_", ""));
+                break;
+            default:
+                appendFunction(functionExpression);
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
index 42383b9..dbedc60 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/openbase/OpenBaseQualifierTranslator.java
@@ -25,6 +25,7 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.PatternMatchNode;
 import org.apache.cayenne.map.DbAttribute;
 
@@ -159,4 +160,18 @@ public class OpenBaseQualifierTranslator extends QualifierTranslator {
 			objectMatchTranslator.setExpression(node);
 		}
 	}
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		switch (functionExpression.getPart()) {
+			case DAY_OF_WEEK:
+			case DAY_OF_MONTH:
+			case DAY_OF_YEAR:
+				// openbase variants are without '_'
+				out.append(functionExpression.getPart().name().replace("_", ""));
+				break;
+			default:
+				appendFunction(functionExpression);
+		}
+	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleQualifierTranslator.java
index 011a33b..fadd468 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/oracle/OracleQualifierTranslator.java
@@ -21,6 +21,7 @@ package org.apache.cayenne.dba.oracle;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.ASTIn;
 import org.apache.cayenne.exp.parser.ASTList;
@@ -152,6 +153,52 @@ public class OracleQualifierTranslator extends TrimmingQualifierTranslator {
 		} else {
 			super.clearLastFunctionArgDivider(functionExpression);
 		}
+
+		if(functionExpression instanceof ASTExtract) {
+			switch (((ASTExtract)functionExpression).getPart()) {
+				case DAY_OF_YEAR:
+					out.append(", 'DDD'");
+					break;
+				case DAY_OF_WEEK:
+					out.append(", 'D'");
+					break;
+				case WEEK:
+					out.append(", 'IW'");
+					break;
+			}
+			out.append(")");
+		}
+	}
+
+	@Override
+	protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+		if (node.getType() == Expression.FUNCTION_CALL) {
+			if (node instanceof ASTExtract) {
+				return false;
+			}
+		}
+
+		return super.parenthesisNeeded(node, parentNode);
+	}
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		switch (functionExpression.getPart()) {
+			// use TO_CHAR(date, format) function for parts that is unsupported by EXTRACT()
+			case DAY_OF_YEAR:
+			case DAY_OF_WEEK:
+			case WEEK:
+				out.append("TO_CHAR(");
+				break;
+			case DAY_OF_MONTH:
+				out.append("EXTRACT(DAY FROM ");
+				break;
+			default:
+				out.append("EXTRACT(");
+				out.append(functionExpression.getPart().name());
+				out.append(" FROM ");
+		}
+
 	}
 
 	/**

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
index 42937bb..3fdc22c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/postgres/PostgresQualifierTranslator.java
@@ -25,6 +25,7 @@ import org.apache.cayenne.CayenneRuntimeException;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.PatternMatchNode;
 
@@ -148,5 +149,41 @@ public class PostgresQualifierTranslator extends TrimmingQualifierTranslator {
 		} else {
 			super.clearLastFunctionArgDivider(functionExpression);
 		}
+
+		if(functionExpression instanceof ASTExtract) {
+			out.append(")");
+		}
+	}
+
+	@Override
+	protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+		if (node.getType() == Expression.FUNCTION_CALL) {
+			if (node instanceof ASTExtract) {
+				return false;
+			}
+		}
+
+		return super.parenthesisNeeded(node, parentNode);
+	}
+
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		out.append("EXTRACT(");
+		switch (functionExpression.getPart()) {
+			case DAY_OF_MONTH:
+				out.append("day");
+				break;
+			case DAY_OF_WEEK:
+				out.append("dow");
+				break;
+			case DAY_OF_YEAR:
+				out.append("doy");
+				break;
+			default:
+				out.append(functionExpression.getPartCamelCaseName());
+		}
+
+		out.append(" FROM ");
 	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteAdapter.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteAdapter.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteAdapter.java
index b390ebc..1796700 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteAdapter.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteAdapter.java
@@ -79,8 +79,8 @@ public class SQLiteAdapter extends JdbcAdapter {
         map.registerType(new SQLiteBigDecimalType());
         map.registerType(new SQLiteFloatType());
         map.registerType(new SQLiteByteArrayType());
-        map.registerType(new SQLiteCalendarType(GregorianCalendar.class));
-        map.registerType(new SQLiteCalendarType(Calendar.class));
+        map.registerType(new SQLiteCalendarType<>(GregorianCalendar.class));
+        map.registerType(new SQLiteCalendarType<>(Calendar.class));
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteDateType.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteDateType.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteDateType.java
index 0dba203..497cc81 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteDateType.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteDateType.java
@@ -39,48 +39,27 @@ import org.apache.cayenne.access.types.UtilDateType;
 // handling fun.
 class SQLiteDateType extends UtilDateType {
 
-    private DateFormat timestampFormat;
-    private DateFormat dateFormat;
-    private DateFormat timeFormat;
+    private final DateFormat timestampFormat;
+    private final DateFormat dateFormat;
+    private final DateFormat timeFormat;
 
     public SQLiteDateType() {
-        timestampFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
+        timestampFormat = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss.SSS");
         dateFormat = new SimpleDateFormat("yyyy-MM-dd");
         timeFormat = new SimpleDateFormat("kk:mm:ss");
     }
 
     @Override
     public Date materializeObject(ResultSet rs, int index, int type) throws Exception {
-
-        String string = rs.getString(index);
-
-        if (string == null) {
-            return null;
-        }
-
-        long ts = getLongTimestamp(string);
-        if (ts >= 0) {
-            return new Date(ts);
-        }
-
-        switch (type) {
-            case Types.TIMESTAMP:
-                return getTimestamp(string);
-            case Types.DATE:
-                return getDate(string);
-            case Types.TIME:
-                return rs.getTime(index);
-            default:
-                return getTimestamp(string);
-        }
+        return parseDate(rs.getString(index), type);
     }
 
     @Override
-    public Date materializeObject(CallableStatement rs, int index, int type)
-            throws Exception {
-
-        String string = rs.getString(index);
+    public Date materializeObject(CallableStatement rs, int index, int type) throws Exception {
+        return parseDate(rs.getString(index), type);
+    }
 
+    protected Date parseDate(String string, int type) throws SQLException {
         if (string == null) {
             return null;
         }
@@ -91,12 +70,10 @@ class SQLiteDateType extends UtilDateType {
         }
 
         switch (type) {
-            case Types.TIMESTAMP:
-                return getTimestamp(string);
-            case Types.DATE:
-                return getDate(string);
             case Types.TIME:
                 return getTime(string);
+            case Types.DATE:
+            case Types.TIMESTAMP:
             default:
                 return getTimestamp(string);
         }
@@ -107,17 +84,9 @@ class SQLiteDateType extends UtilDateType {
             synchronized (timestampFormat) {
                 return timestampFormat.parse(string);
             }
-        }
-        catch (ParseException e) {
+        } catch (ParseException e) {
             // also try date format...
-            try {
-                synchronized (dateFormat) {
-                    return dateFormat.parse(string);
-                }
-            }
-            catch (ParseException e1) {
-                throw new SQLException("Unparsable timestamp string: " + string);
-            }
+            return getDate(string);
         }
     }
 
@@ -126,9 +95,8 @@ class SQLiteDateType extends UtilDateType {
             synchronized (dateFormat) {
                 return dateFormat.parse(string);
             }
-        }
-        catch (ParseException e) {
-            throw new SQLException("Unparsable date string: " + string);
+        } catch (ParseException e) {
+            throw new SQLException("Unparsable date/time string: " + string);
         }
     }
 
@@ -137,17 +105,15 @@ class SQLiteDateType extends UtilDateType {
             synchronized (timeFormat) {
                 return timeFormat.parse(string);
             }
-        }
-        catch (ParseException e) {
-            throw new SQLException("Unparsable time string: " + string);
+        } catch (ParseException e) {
+            return getTimestamp(string);
         }
     }
 
     protected long getLongTimestamp(String string) {
         try {
             return Long.parseLong(string);
-        }
-        catch (NumberFormatException e) {
+        } catch (NumberFormatException e) {
             return -1;
         }
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteQualifierTranslator.java
index bc2bb2e..d31019b 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlite/SQLiteQualifierTranslator.java
@@ -22,6 +22,7 @@ package org.apache.cayenne.dba.sqlite;
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.exp.parser.Node;
 
@@ -91,6 +92,65 @@ public class SQLiteQualifierTranslator extends QualifierTranslator {
             default:
                 super.clearLastFunctionArgDivider(functionExpression);
         }
+        if(functionExpression instanceof ASTExtract) {
+            out.append(") as integer)");
+        }
+    }
+
+    @Override
+    protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+        if (node.getType() == Expression.FUNCTION_CALL) {
+            if (node instanceof ASTExtract) {
+                return false;
+            }
+        }
+
+        return super.parenthesisNeeded(node, parentNode);
+    }
+
+
+    /**
+     * Translates to cast(strftime('format', column) as integer).
+     * Depends on connection property "date_class", can be set in connection URL (date_class=text).
+     *
+     * https://www.sqlite.org/lang_datefunc.html
+     */
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        out.append("cast(strftime(");
+
+        switch (functionExpression.getPart()) {
+            case YEAR:
+                out.append("'%Y'");
+                break;
+            case MONTH:
+                out.append("'%m'");
+                break;
+            case WEEK:
+                out.append("'%W'");
+                break;
+            case DAY:
+            case DAY_OF_MONTH:
+                out.append("'%d'");
+                break;
+            case DAY_OF_WEEK:
+                out.append("'%w'");
+                break;
+            case DAY_OF_YEAR:
+                out.append("'%j'");
+                break;
+            case HOUR:
+                out.append("'%H'");
+                break;
+            case MINUTE:
+                out.append("'%M'");
+                break;
+            case SECOND:
+                out.append("'%S'");
+                break;
+        }
+
+        out.append(", ");
     }
 
     private void swapNodeChildren(Node node, int i, int j) {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
index 9def833..9847742 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sqlserver/SQLServerTrimmingQualifierTranslator.java
@@ -21,6 +21,7 @@ package org.apache.cayenne.dba.sqlserver;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
 import org.apache.cayenne.access.translator.select.TrimmingQualifierTranslator;
 import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 import org.apache.cayenne.map.DbAttribute;
 
@@ -168,5 +169,39 @@ class SQLServerTrimmingQualifierTranslator extends TrimmingQualifierTranslator {
 				out.append(")");
 			}
 		}
+
+		if(functionExpression instanceof ASTExtract) {
+			out.append(")");
+		}
+	}
+
+	@Override
+	protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+		if (node.getType() == Expression.FUNCTION_CALL) {
+			if (node instanceof ASTExtract) {
+				return false;
+			}
+		}
+
+		return super.parenthesisNeeded(node, parentNode);
+	}
+
+	@Override
+	protected void appendExtractFunction(ASTExtract functionExpression) {
+		out.append("DATEPART(");
+		switch (functionExpression.getPart()) {
+			case DAY_OF_MONTH:
+				out.append("DAY");
+				break;
+			case DAY_OF_WEEK:
+				out.append("WEEKDAY");
+				break;
+			case DAY_OF_YEAR:
+				out.append("DAYOFYEAR");
+				break;
+			default:
+				out.append(functionExpression.getPart().name());
+		}
+		out.append(" , ");
 	}
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseQualifierTranslator.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseQualifierTranslator.java b/cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseQualifierTranslator.java
index 1ad939e..0f6e239 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseQualifierTranslator.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/dba/sybase/SybaseQualifierTranslator.java
@@ -21,6 +21,8 @@ package org.apache.cayenne.dba.sybase;
 
 import org.apache.cayenne.access.translator.select.QualifierTranslator;
 import org.apache.cayenne.access.translator.select.QueryAssembler;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTFunctionCall;
 
 /**
@@ -74,5 +76,39 @@ public class SybaseQualifierTranslator extends QualifierTranslator {
             default:
                 super.clearLastFunctionArgDivider(functionExpression);
         }
+
+        if(functionExpression instanceof ASTExtract) {
+            out.append(")");
+        }
+    }
+
+    @Override
+    protected boolean parenthesisNeeded(Expression node, Expression parentNode) {
+        if (node.getType() == Expression.FUNCTION_CALL) {
+            if (node instanceof ASTExtract) {
+                return false;
+            }
+        }
+
+        return super.parenthesisNeeded(node, parentNode);
+    }
+
+    @Override
+    protected void appendExtractFunction(ASTExtract functionExpression) {
+        out.append("datepart(");
+        switch (functionExpression.getPart()) {
+            case DAY_OF_MONTH:
+                out.append("day");
+                break;
+            case DAY_OF_WEEK:
+                out.append("weekday");
+                break;
+            case DAY_OF_YEAR:
+                out.append("dayofyear");
+                break;
+            default:
+                out.append(functionExpression.getPart().name().toLowerCase());
+        }
+        out.append(" , ");
     }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
index e4cbf07..114fb1d 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/FunctionExpressionFactory.java
@@ -26,6 +26,7 @@ import org.apache.cayenne.exp.parser.ASTCount;
 import org.apache.cayenne.exp.parser.ASTCurrentDate;
 import org.apache.cayenne.exp.parser.ASTCurrentTime;
 import org.apache.cayenne.exp.parser.ASTCurrentTimestamp;
+import org.apache.cayenne.exp.parser.ASTExtract;
 import org.apache.cayenne.exp.parser.ASTLength;
 import org.apache.cayenne.exp.parser.ASTLocate;
 import org.apache.cayenne.exp.parser.ASTLower;
@@ -370,4 +371,158 @@ public class FunctionExpressionFactory {
     public static Expression currentTimestamp() {
         return new ASTCurrentTimestamp();
     }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return year(exp) function expression
+     */
+    public static Expression yearExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.YEAR);
+    }
+
+    /**
+     * @param path String path
+     * @return year(path) function expression
+     */
+    public static Expression yearExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.YEAR);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return month(exp) function expression
+     */
+    public static Expression monthExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.MONTH);
+    }
+
+    /**
+     * @param path String path
+     * @return month(path) function expression
+     */
+    public static Expression monthExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.MONTH);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return week(exp) function expression
+     */
+    public static Expression weekExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.WEEK);
+    }
+
+    /**
+     * @param path String path
+     * @return week(path) function expression
+     */
+    public static Expression weekExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.WEEK);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return dayOfYear(exp) function expression
+     */
+    public static Expression dayOfYearExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.DAY_OF_YEAR);
+    }
+
+    /**
+     * @param path String path
+     * @return dayOfYear(path) function expression
+     */
+    public static Expression dayOfYearExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.DAY_OF_YEAR);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return dayOfMonth(exp) function expression, synonym for day()
+     */
+    public static Expression dayOfMonthExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.DAY_OF_MONTH);
+    }
+
+    /**
+     * @param path String path
+     * @return dayOfMonth(path) function expression, synonym for day()
+     */
+    public static Expression dayOfMonthExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.DAY_OF_MONTH);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return dayOfWeek(exp) function expression
+     */
+    public static Expression dayOfWeekExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.DAY_OF_WEEK);
+    }
+
+    /**
+     * @param path String path
+     * @return dayOfWeek(path) function expression
+     */
+    public static Expression dayOfWeekExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.DAY_OF_WEEK);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return hour(exp) function expression
+     */
+    public static Expression hourExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.HOUR);
+    }
+
+    /**
+     * @param path String path
+     * @return hour(path) function expression
+     */
+    public static Expression hourExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.HOUR);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return minute(exp) function expression
+     */
+    public static Expression minuteExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.MINUTE);
+    }
+
+    /**
+     * @param path String path
+     * @return minute(path) function expression
+     */
+    public static Expression minuteExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.MINUTE);
+    }
+
+    /**
+     * @param exp date/timestamp expression
+     * @return second(exp) function expression
+     */
+    public static Expression secondExp(Expression exp) {
+        return extractExp(exp, ASTExtract.DateTimePart.SECOND);
+    }
+
+    /**
+     * @param path String path
+     * @return second(path) function expression
+     */
+    public static Expression secondExp(String path) {
+        return extractExp(path, ASTExtract.DateTimePart.SECOND);
+    }
+
+    static Expression extractExp(String path, ASTExtract.DateTimePart part) {
+        return extractExp(ExpressionFactory.pathExp(path), part);
+    }
+
+    static Expression extractExp(Expression exp, ASTExtract.DateTimePart part) {
+        ASTExtract extract = new ASTExtract(exp);
+        extract.setPart(part);
+        return extract;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java
index e453e8f..73743df 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentDate.java
@@ -53,11 +53,6 @@ public class ASTCurrentDate extends ASTFunctionCall {
     }
 
     @Override
-    protected void appendFunctionNameAsString(Appendable out) throws IOException {
-        out.append("currentDate");
-    }
-
-    @Override
     public Expression shallowCopy() {
         return new ASTCurrentDate(id);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java
index feb9dfa..6cee32c 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTime.java
@@ -53,11 +53,6 @@ public class ASTCurrentTime extends ASTFunctionCall {
     }
 
     @Override
-    protected void appendFunctionNameAsString(Appendable out) throws IOException {
-        out.append("currentTime");
-    }
-
-    @Override
     public Expression shallowCopy() {
         return new ASTCurrentTime(id);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java
index df55492..9edf263 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTCurrentTimestamp.java
@@ -53,11 +53,6 @@ public class ASTCurrentTimestamp extends ASTFunctionCall {
     }
 
     @Override
-    protected void appendFunctionNameAsString(Appendable out) throws IOException {
-        out.append("currentTimestamp");
-    }
-
-    @Override
     public Expression shallowCopy() {
         return new ASTCurrentTimestamp(id);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTExtract.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTExtract.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTExtract.java
new file mode 100644
index 0000000..184d298
--- /dev/null
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTExtract.java
@@ -0,0 +1,125 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.
+ ****************************************************************/
+
+package org.apache.cayenne.exp.parser;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.exp.Expression;
+
+public class ASTExtract extends ASTFunctionCall {
+
+    /**
+     * Available components of date/time.
+     * Names must be in sync with tokens used in dateTimeExtractingFunction() rule in ExpressionParser.jjt
+     */
+    public enum DateTimePart {
+        YEAR, MONTH, WEEK,
+        // day options, day is synonym for dayOfMonth
+        DAY_OF_YEAR, DAY, DAY_OF_MONTH, DAY_OF_WEEK,
+        HOUR, MINUTE, SECOND
+    }
+
+    /**
+     * Map from camelCase name to enum elements.
+     * @see ASTFunctionCall#nameToCamelCase(String)
+     */
+    private static final Map<String, DateTimePart> NAME_TO_PART = new HashMap<>();
+    static {
+        for(DateTimePart part : DateTimePart.values()) {
+            NAME_TO_PART.put(nameToCamelCase(part.name()), part);
+        }
+    }
+
+    /**
+     * camelCase name, found in ExpressionParser.jjt tokens
+     */
+    private String partName;
+
+    private DateTimePart part;
+
+    ASTExtract(int id) {
+        super(id, "EXTRACT");
+    }
+
+    public ASTExtract(Expression expression) {
+        super(ExpressionParserTreeConstants.JJTEXTRACT, "EXTRACT", expression);
+    }
+
+    @Override
+    public String getFunctionName() {
+        return part.name();
+    }
+
+    @Override
+    protected void appendFunctionNameAsString(Appendable out) throws IOException {
+        out.append(partName);
+    }
+
+    /**
+     * This method is used by {@link ExpressionParser}
+     * @param partToken {@link Token#image} from {@link ExpressionParser}
+     */
+    void setPartToken(String partToken) {
+        part = NAME_TO_PART.get(partToken);
+        if(part == null) {
+            throw new CayenneRuntimeException("Unknown timestamp part: " + partToken);
+        }
+        this.partName = partToken;
+    }
+
+    /**
+     * This method is used by FunctionExpressionFactory
+     * @param part date/time part to extract
+     */
+    public void setPart(DateTimePart part) {
+        this.part = part;
+        this.partName = nameToCamelCase(part.name());
+    }
+
+    public DateTimePart getPart() {
+        return part;
+    }
+
+    public String getPartCamelCaseName() {
+        return partName;
+    }
+
+    @Override
+    public Expression shallowCopy() {
+        ASTExtract copy = new ASTExtract(id);
+        copy.partName = partName;
+        copy.part = part;
+        return copy;
+    }
+
+    @Override
+    protected int getRequiredChildrenCount() {
+        return 1;
+    }
+
+    @Override
+    protected Object evaluateSubNode(Object o, Object[] evaluatedChildren) throws Exception {
+        return null;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java
index d31c148..3766793 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ASTFunctionCall.java
@@ -80,7 +80,7 @@ public abstract class ASTFunctionCall extends EvaluatedNode {
     }
 
     protected void appendFunctionNameAsString(Appendable out) throws IOException {
-        out.append(getFunctionName().toLowerCase());
+        out.append(nameToCamelCase(getFunctionName()));
     }
 
     @Override
@@ -103,4 +103,26 @@ public abstract class ASTFunctionCall extends EvaluatedNode {
         super.appendChildrenAsEJBQL(parameterAccumulator, out, rootId);
         out.append(")");
     }
+
+    /**
+     *
+     * @param functionName in UPPER_UNDERSCORE convention
+     * @return functionName in camelCase convention
+     */
+    protected static String nameToCamelCase(String functionName) {
+        String[] parts = functionName.split("_");
+        StringBuilder sb = new StringBuilder();
+        boolean first = true;
+        for(String part : parts) {
+            if(first) {
+                sb.append(part.toLowerCase());
+                first = false;
+            } else {
+                char[] chars = part.toLowerCase().toCharArray();
+                chars[0] = Character.toTitleCase(chars[0]);
+                sb.append(chars);
+            }
+        }
+        return sb.toString();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
index 732110d..ff0fde8 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParser.java
@@ -184,10 +184,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case CURRENT_DATE:
     case CURRENT_TIME:
     case CURRENT_TIMESTAMP:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case SINGLE_QUOTED_STRING:
     case DOUBLE_QUOTED_STRING:
@@ -251,10 +261,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case CURRENT_DATE:
     case CURRENT_TIME:
     case CURRENT_TIMESTAMP:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case SINGLE_QUOTED_STRING:
     case DOUBLE_QUOTED_STRING:
@@ -524,7 +544,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                  jjtree.openNodeScope(jjtn011);
           try {
             switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-            case 54:
+            case 64:
               namedParameter();
               break;
             case 16:
@@ -683,7 +703,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                        jjtree.openNodeScope(jjtn003);
       try {
         switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-        case 54:
+        case 64:
           namedParameter();
           break;
         case 16:
@@ -803,10 +823,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case ABS:
     case SQRT:
     case MOD:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case INT_LITERAL:
     case FLOAT_LITERAL:
@@ -854,9 +884,9 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
 
   final public void stringParameter() throws ParseException {
     switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
-    case 55:
-    case 56:
-    case 57:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
       pathExpression();
       break;
@@ -947,10 +977,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case CURRENT_DATE:
     case CURRENT_TIME:
     case CURRENT_TIMESTAMP:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case SINGLE_QUOTED_STRING:
     case DOUBLE_QUOTED_STRING:
@@ -1027,22 +1067,22 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                                    }
       }
       break;
-    case 54:
+    case 64:
       namedParameter();
       break;
     case INT_LITERAL:
       jj_consume_token(INT_LITERAL);
-                          ASTScalar jjtn003 = new ASTScalar(JJTSCALAR);
-                          boolean jjtc003 = true;
-                          jjtree.openNodeScope(jjtn003);
+                            ASTScalar jjtn003 = new ASTScalar(JJTSCALAR);
+                            boolean jjtc003 = true;
+                            jjtree.openNodeScope(jjtn003);
       try {
-                          jjtree.closeNodeScope(jjtn003,  0);
-                          jjtc003 = false;
-                          jjtn003.setValue(token_source.literalValue);
-      } finally {
-                          if (jjtc003) {
                             jjtree.closeNodeScope(jjtn003,  0);
-                          }
+                            jjtc003 = false;
+                            jjtn003.setValue(token_source.literalValue);
+      } finally {
+                            if (jjtc003) {
+                              jjtree.closeNodeScope(jjtn003,  0);
+                            }
       }
       break;
     case FLOAT_LITERAL:
@@ -1062,17 +1102,17 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
       break;
     case TRUE:
       jj_consume_token(TRUE);
-                   ASTScalar jjtn005 = new ASTScalar(JJTSCALAR);
-                   boolean jjtc005 = true;
-                   jjtree.openNodeScope(jjtn005);
+                    ASTScalar jjtn005 = new ASTScalar(JJTSCALAR);
+                    boolean jjtc005 = true;
+                    jjtree.openNodeScope(jjtn005);
       try {
-                   jjtree.closeNodeScope(jjtn005,  0);
-                   jjtc005 = false;
-                   jjtn005.setValue(true);
+                    jjtree.closeNodeScope(jjtn005,  0);
+                    jjtc005 = false;
+                    jjtn005.setValue(true);
       } finally {
-                   if (jjtc005) {
-                     jjtree.closeNodeScope(jjtn005,  0);
-                   }
+                    if (jjtc005) {
+                      jjtree.closeNodeScope(jjtn005,  0);
+                    }
       }
       break;
     case FALSE:
@@ -1459,10 +1499,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case ABS:
     case SQRT:
     case MOD:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case INT_LITERAL:
     case FLOAT_LITERAL:
@@ -1511,10 +1561,20 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case ABS:
     case SQRT:
     case MOD:
-    case 54:
-    case 55:
-    case 56:
-    case 57:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+    case 64:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
     case INT_LITERAL:
     case FLOAT_LITERAL:
@@ -1599,7 +1659,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                             }
       }
       break;
-    case 54:
+    case 64:
       namedParameter();
       break;
     case LENGTH:
@@ -1607,11 +1667,21 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case ABS:
     case SQRT:
     case MOD:
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
       functionsReturningNumerics();
       break;
-    case 55:
-    case 56:
-    case 57:
+    case 65:
+    case 66:
+    case 67:
     case PROPERTY_PATH:
       pathExpression();
       break;
@@ -1842,6 +1912,18 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     case MOD:
       mod();
       break;
+    case YEAR:
+    case MONTH:
+    case WEEK:
+    case DAY_OF_YEAR:
+    case DAY:
+    case DAY_OF_MONTH:
+    case DAY_OF_WEEK:
+    case HOUR:
+    case MINUTE:
+    case SECOND:
+      dateTimeExtractingFunction();
+      break;
     default:
       jj_la1[35] = jj_gen;
       jj_consume_token(-1);
@@ -2067,9 +2149,9 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
       case ASTERISK:
         asterisk();
         break;
-      case 55:
-      case 56:
-      case 57:
+      case 65:
+      case 66:
+      case 67:
       case PROPERTY_PATH:
         pathExpression();
         break;
@@ -2290,9 +2372,77 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     }
   }
 
+/* Date/time parts extracting function */
+  final public void dateTimeExtractingFunction() throws ParseException {
+                                                 /*@bgen(jjtree) #Extract( 1) */
+    ASTExtract jjtn000 = new ASTExtract(JJTEXTRACT);
+    boolean jjtc000 = true;
+    jjtree.openNodeScope(jjtn000);Token t;
+    try {
+      switch ((jj_ntk==-1)?jj_ntk():jj_ntk) {
+      case YEAR:
+        t = jj_consume_token(YEAR);
+        break;
+      case MONTH:
+        t = jj_consume_token(MONTH);
+        break;
+      case WEEK:
+        t = jj_consume_token(WEEK);
+        break;
+      case DAY_OF_YEAR:
+        t = jj_consume_token(DAY_OF_YEAR);
+        break;
+      case DAY:
+        t = jj_consume_token(DAY);
+        break;
+      case DAY_OF_MONTH:
+        t = jj_consume_token(DAY_OF_MONTH);
+        break;
+      case DAY_OF_WEEK:
+        t = jj_consume_token(DAY_OF_WEEK);
+        break;
+      case HOUR:
+        t = jj_consume_token(HOUR);
+        break;
+      case MINUTE:
+        t = jj_consume_token(MINUTE);
+        break;
+      case SECOND:
+        t = jj_consume_token(SECOND);
+        break;
+      default:
+        jj_la1[40] = jj_gen;
+        jj_consume_token(-1);
+        throw new ParseException();
+      }
+        jjtn000.setPartToken(t.image);
+      jj_consume_token(16);
+      pathExpression();
+      jj_consume_token(17);
+    } catch (Throwable jjte000) {
+      if (jjtc000) {
+        jjtree.clearNodeScope(jjtn000);
+        jjtc000 = false;
+      } else {
+        jjtree.popNode();
+      }
+      if (jjte000 instanceof RuntimeException) {
+        {if (true) throw (RuntimeException)jjte000;}
+      }
+      if (jjte000 instanceof ParseException) {
+        {if (true) throw (ParseException)jjte000;}
+      }
+      {if (true) throw (Error)jjte000;}
+    } finally {
+      if (jjtc000) {
+        jjtree.closeNodeScope(jjtn000,  1);
+      }
+    }
+  }
+
   final public void namedParameter() throws ParseException {
         Token t;
-    jj_consume_token(54);
+    jj_consume_token(64);
     t = jj_consume_token(PROPERTY_PATH);
                                   ASTNamedParameter jjtn001 = new ASTNamedParameter(JJTNAMEDPARAMETER);
                                   boolean jjtc001 = true;
@@ -2326,8 +2476,8 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                                    }
       }
       break;
-    case 55:
-      jj_consume_token(55);
+    case 65:
+      jj_consume_token(65);
       t = jj_consume_token(PROPERTY_PATH);
                                    ASTObjPath jjtn002 = new ASTObjPath(JJTOBJPATH);
                                    boolean jjtc002 = true;
@@ -2342,8 +2492,8 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                                    }
       }
       break;
-    case 56:
-      jj_consume_token(56);
+    case 66:
+      jj_consume_token(66);
       t = jj_consume_token(PROPERTY_PATH);
                                    ASTDbPath jjtn003 = new ASTDbPath(JJTDBPATH);
                                    boolean jjtc003 = true;
@@ -2358,8 +2508,8 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
                                    }
       }
       break;
-    case 57:
-      jj_consume_token(57);
+    case 67:
+      jj_consume_token(67);
       t = jj_consume_token(PROPERTY_PATH);
                                    ASTScalar jjtn004 = new ASTScalar(JJTSCALAR);
                                    boolean jjtc004 = true;
@@ -2375,7 +2525,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
       }
       break;
     default:
-      jj_la1[40] = jj_gen;
+      jj_la1[41] = jj_gen;
       jj_consume_token(-1);
       throw new ParseException();
     }
@@ -2390,7 +2540,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
   public Token jj_nt;
   private int jj_ntk;
   private int jj_gen;
-  final private int[] jj_la1 = new int[41];
+  final private int[] jj_la1 = new int[42];
   static private int[] jj_la1_0;
   static private int[] jj_la1_1;
   static private int[] jj_la1_2;
@@ -2400,13 +2550,13 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
       jj_la1_init_2();
    }
    private static void jj_la1_init_0() {
-      jj_la1_0 = new int[] {0x2,0x4,0x18,0x16010018,0x60,0x180,0x10000,0x4fff8,0x4fff8,0x16010000,0x18,0x10000,0x4e000,0x80000,0x16010000,0x0,0x0,0x16010000,0x0,0x100000,0x200000,0x400000,0x1800000,0x1800000,0x6000000,0x6000000,0x8000000,0x8000000,0x16010000,0x2000000,0x6010000,0x10000,0x0,0x80000,0x80000,0x0,0x80000,0x0,0x0,0x0,0x0,};
+      jj_la1_0 = new int[] {0x2,0x4,0x18,0x16010018,0x60,0x180,0x10000,0x4fff8,0x4fff8,0x16010000,0x18,0x10000,0x4e000,0x80000,0x16010000,0x0,0x0,0x16010000,0x0,0x100000,0x200000,0x400000,0x1800000,0x1800000,0x6000000,0x6000000,0x8000000,0x8000000,0x16010000,0x2000000,0x6010000,0x10000,0x0,0x80000,0x80000,0x0,0x80000,0x0,0x0,0x0,0x0,0x0,};
    }
    private static void jj_la1_init_1() {
-      jj_la1_1 = new int[] {0x0,0x0,0x0,0xbfffffe,0x0,0x0,0x400000,0x0,0x0,0xbfffffe,0x0,0x400000,0x0,0x0,0xbfffff2,0xb803e00,0x3e00,0xbfffffe,0x40000c,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x4000000,0x4000000,0xbc7c000,0x0,0xbc7c000,0xbc7c000,0x3e00,0x0,0x0,0x7c000,0x0,0x1f0,0xf800000,0x380000,0xb800000,};
+      jj_la1_1 = new int[] {0x0,0x0,0x0,0xfffffffe,0x0,0x0,0x0,0x0,0x0,0xfffffffe,0x0,0x0,0x0,0x0,0xfffffff2,0x3e00,0x3e00,0xfffffffe,0xc,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xffc7c000,0x0,0xffc7c000,0xffc7c000,0x3e00,0x0,0x0,0xffc7c000,0x0,0x1f0,0x0,0x380000,0xffc00000,0x0,};
    }
    private static void jj_la1_init_2() {
-      jj_la1_2 = new int[] {0x0,0x0,0x0,0x1c8,0x0,0x0,0x0,0x0,0x0,0x1c8,0x0,0x0,0x0,0x0,0x1c8,0x48,0x48,0x1c8,0x1c8,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x180,0x0,0x180,0x180,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,};
+      jj_la1_2 = new int[] {0x0,0x0,0x0,0x7202f,0x0,0x0,0x1,0x0,0x0,0x7202f,0x0,0x1,0x0,0x0,0x7202f,0x1202e,0x12000,0x7202f,0x72001,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x10,0x10,0x6002f,0x0,0x6002f,0x6002f,0x0,0x0,0x0,0x0,0x0,0x0,0x3e,0x0,0x0,0x2e,};
    }
 
   /** Constructor with InputStream. */
@@ -2420,7 +2570,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -2435,7 +2585,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   /** Constructor. */
@@ -2445,7 +2595,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -2456,7 +2606,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   /** Constructor with generated Token Manager. */
@@ -2465,7 +2615,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     token = new Token();
     jj_ntk = -1;
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   /** Reinitialise. */
@@ -2475,7 +2625,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
     jj_ntk = -1;
     jjtree.reset();
     jj_gen = 0;
-    for (int i = 0; i < 41; i++) jj_la1[i] = -1;
+    for (int i = 0; i < 42; i++) jj_la1[i] = -1;
   }
 
   private Token jj_consume_token(int kind) throws ParseException {
@@ -2526,12 +2676,12 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
   /** Generate ParseException. */
   public ParseException generateParseException() {
     jj_expentries.clear();
-    boolean[] la1tokens = new boolean[77];
+    boolean[] la1tokens = new boolean[87];
     if (jj_kind >= 0) {
       la1tokens[jj_kind] = true;
       jj_kind = -1;
     }
-    for (int i = 0; i < 41; i++) {
+    for (int i = 0; i < 42; i++) {
       if (jj_la1[i] == jj_gen) {
         for (int j = 0; j < 32; j++) {
           if ((jj_la1_0[i] & (1<<j)) != 0) {
@@ -2546,7 +2696,7 @@ public class ExpressionParser/*@bgen(jjtree)*/implements ExpressionParserTreeCon
         }
       }
     }
-    for (int i = 0; i < 77; i++) {
+    for (int i = 0; i < 87; i++) {
       if (la1tokens[i]) {
         jj_expentry = new int[1];
         jj_expentry[0] = i;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/05a77250/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserConstants.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserConstants.java b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserConstants.java
index a4c1a77..18c00e2 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserConstants.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/exp/parser/ExpressionParserConstants.java
@@ -73,35 +73,55 @@ public interface ExpressionParserConstants {
   /** RegularExpression Id. */
   int CURRENT_TIMESTAMP = 53;
   /** RegularExpression Id. */
-  int ASTERISK = 58;
+  int YEAR = 54;
   /** RegularExpression Id. */
-  int PROPERTY_PATH = 59;
+  int MONTH = 55;
   /** RegularExpression Id. */
-  int IDENTIFIER = 60;
+  int WEEK = 56;
   /** RegularExpression Id. */
-  int LETTER = 61;
+  int DAY_OF_YEAR = 57;
   /** RegularExpression Id. */
-  int DIGIT = 62;
+  int DAY = 58;
   /** RegularExpression Id. */
-  int ESC = 65;
+  int DAY_OF_MONTH = 59;
   /** RegularExpression Id. */
-  int SINGLE_QUOTED_STRING = 67;
+  int DAY_OF_WEEK = 60;
   /** RegularExpression Id. */
-  int STRING_ESC = 68;
+  int HOUR = 61;
   /** RegularExpression Id. */
-  int DOUBLE_QUOTED_STRING = 70;
+  int MINUTE = 62;
   /** RegularExpression Id. */
-  int INT_LITERAL = 71;
+  int SECOND = 63;
   /** RegularExpression Id. */
-  int FLOAT_LITERAL = 72;
+  int ASTERISK = 68;
   /** RegularExpression Id. */
-  int DEC_FLT = 73;
+  int PROPERTY_PATH = 69;
   /** RegularExpression Id. */
-  int DEC_DIGITS = 74;
+  int IDENTIFIER = 70;
   /** RegularExpression Id. */
-  int EXPONENT = 75;
+  int LETTER = 71;
   /** RegularExpression Id. */
-  int FLT_SUFF = 76;
+  int DIGIT = 72;
+  /** RegularExpression Id. */
+  int ESC = 75;
+  /** RegularExpression Id. */
+  int SINGLE_QUOTED_STRING = 77;
+  /** RegularExpression Id. */
+  int STRING_ESC = 78;
+  /** RegularExpression Id. */
+  int DOUBLE_QUOTED_STRING = 80;
+  /** RegularExpression Id. */
+  int INT_LITERAL = 81;
+  /** RegularExpression Id. */
+  int FLOAT_LITERAL = 82;
+  /** RegularExpression Id. */
+  int DEC_FLT = 83;
+  /** RegularExpression Id. */
+  int DEC_DIGITS = 84;
+  /** RegularExpression Id. */
+  int EXPONENT = 85;
+  /** RegularExpression Id. */
+  int FLT_SUFF = 86;
 
   /** Lexical state. */
   int DEFAULT = 0;
@@ -166,6 +186,16 @@ public interface ExpressionParserConstants {
     "\"currentDate\"",
     "\"currentTime\"",
     "<CURRENT_TIMESTAMP>",
+    "\"year\"",
+    "\"month\"",
+    "\"week\"",
+    "\"dayOfYear\"",
+    "\"day\"",
+    "\"dayOfMonth\"",
+    "\"dayOfWeek\"",
+    "\"hour\"",
+    "\"minute\"",
+    "\"second\"",
     "\"$\"",
     "\"obj:\"",
     "\"db:\"",
@@ -178,10 +208,10 @@ public interface ExpressionParserConstants {
     "\"\\\'\"",
     "\"\\\"\"",
     "<ESC>",
-    "<token of kind 66>",
+    "<token of kind 76>",
     "\"\\\'\"",
     "<STRING_ESC>",
-    "<token of kind 69>",
+    "<token of kind 79>",
     "\"\\\"\"",
     "<INT_LITERAL>",
     "<FLOAT_LITERAL>",