EMPIREDB-381 Postgres improvement No 1
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBColumn.java b/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
index 849a767..c8e68d4 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBColumn.java
@@ -25,7 +25,9 @@
 import org.apache.empire.commons.Options;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.Column;
+import org.apache.empire.data.DataType;
 import org.apache.empire.db.exceptions.DatabaseNotOpenException;
+import org.apache.empire.db.expr.column.DBValueExpr;
 import org.apache.empire.db.expr.set.DBSetExpr;
 import org.apache.empire.dbms.DBMSHandler;
 import org.apache.empire.exceptions.ObjectNotValidException;
@@ -309,6 +311,16 @@
     }
 
     /**
+     * Returns the name of the column as a value expression
+     * This may be used to reference a parent column in a subquery 
+     * @return the column value expression
+     */
+    public DBValueExpr value()
+    {
+        return new DBValueExpr(getDatabase(), this, DataType.UNKNOWN);    
+    }
+
+    /**
      * Returns the full qualified column name.
      *
      * @return the full qualified column name
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
index 63b0270..26d5284 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBColumnExpr.java
@@ -730,7 +730,7 @@
      */
     public DBColumnExpr modulo(Object divisor)
     {
-        return getExprFromPhrase(DBSqlPhrase.SQL_FUNC_MODULO, new Object[] { divisor });
+        return getExprFromPhrase(DBSqlPhrase.SQL_FUNC_MOD, new Object[] { divisor });
     }
 
     /**
@@ -1094,9 +1094,19 @@
      * @param separator the separator between string
      * @return the new DBFuncExpr object
      */
-    public DBColumnExpr strAgg(String separator)
+    public DBColumnExpr stringAgg(String separator, DBOrderByExpr orderBy)
     {
-        return getExprFromPhrase(DBSqlPhrase.SQL_FUNC_STRAGG, new Object[] { separator });
+        return getExprFromPhrase(DBSqlPhrase.SQL_FUNC_STRAGG, new Object[] { separator, orderBy });
+    }
+
+    /**
+     * Creates and returns string aggregation expression
+     * @param separator the separator between string
+     * @return the new DBFuncExpr object
+     */
+    public DBColumnExpr stringAgg(String separator)
+    {
+        return stringAgg(separator, this.asc());
     }
     
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
index c76ba31..a8927db 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommand.java
@@ -239,9 +239,6 @@
    	{
    	    if (cmdParams==null)
    	        return; // Nothing to do
-   	    // unwrap
-   	    if (cmpExpr instanceof Unwrappable<?>)
-   	        cmpExpr = (DBCompareExpr)((Unwrappable<?>)cmpExpr).unwrap();
    	    // check type
    	    if (cmpExpr instanceof DBCompareColExpr)
    	    {   // DBCompareColExpr
@@ -258,6 +255,10 @@
         {   // DBCompareNotExpr
             removeCommandParams(((DBCompareNotExpr)cmpExpr).getExpr());
         }
+        else if ((cmpExpr instanceof Unwrappable<?>) && ((Unwrappable<?>)cmpExpr).isWrapper())
+        {   // unwrap
+            removeCommandParams((DBCompareExpr)((Unwrappable<?>)cmpExpr).unwrap());
+        }
    	}
 
     /**
@@ -1384,7 +1385,7 @@
             if (!(cmp instanceof DBCompareColExpr))
             	continue;
             // Compare columns
-            DBColumnExpr cmpCol = ((DBCompareColExpr)cmp).getColumn();
+            DBColumnExpr cmpCol = ((DBCompareColExpr)cmp).getColumnExpr();
             if (ObjectUtils.compareEqual(cmpCol, colExpr))
             {   // Check if we replace a DBCommandParam
                 removeCommandParams(cmp);
@@ -1559,15 +1560,12 @@
         return buf.toString();
     }
     
+    @SuppressWarnings("unchecked")
     protected void appendCompareColExprs(DBRowSet table, DBCompareExpr expr, List<DBCompareColExpr> list)
     {
-        // unwrap
-        if (expr instanceof Unwrappable<?>)
-            expr = (DBCompareExpr)((Unwrappable<?>)expr).unwrap();
-        // check type
         if (expr instanceof DBCompareColExpr)
         {   // DBCompareColExpr
-            DBColumn column = ((DBCompareColExpr)expr).getColumn().getUpdateColumn();
+            DBColumn column = ((DBCompareColExpr)expr).getColumnExpr().getUpdateColumn();
             if (column!=null && column.getRowSet().equals(table) && !hasSetExprOn(column))
                 list.add((DBCompareColExpr)expr);
         }
@@ -1580,6 +1578,10 @@
         {   // DBCompareNotExpr
             appendCompareColExprs(table, ((DBCompareNotExpr)expr).getExpr(),  list);
         }
+        else if ((expr instanceof Unwrappable<?>) && ((Unwrappable<?>)expr).isWrapper())
+        {   // unwrap
+            appendCompareColExprs(table, ((Unwrappable<DBCompareExpr>)expr).unwrap(), list);
+        }
     }
 
     /**
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
index 934e3f4..9a8beb7 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
@@ -25,6 +25,7 @@
 
 import org.apache.empire.commons.Options;
 import org.apache.empire.data.DataType;
+import org.apache.empire.db.expr.column.DBCmdResultExpr;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
 import org.apache.empire.db.expr.order.DBOrderByExpr;
 import org.apache.empire.dbms.DBMSHandler;
@@ -367,6 +368,19 @@
     public abstract DataType getDataType();
     
     /**
+     * Returns a ColumnExpr for the result of the query
+     * If the command must have exactly one select column otherwise a NotSupportedException is thrown;
+     * @return the result expression
+     */
+    public DBColumnExpr result()
+    {   try {
+            return new DBCmdResultExpr(this);        
+        } catch(InvalidArgumentException e) {
+            throw new NotSupportedException(this, "result");
+        }
+    }
+    
+    /**
      * Creates the SQL-Command.
      * 
      * @param buf the SQL-Command
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index 553ff8e..5547767 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -496,12 +496,12 @@
                 if (cmp instanceof DBCompareColExpr)

                 { 	// Check whether constraint belongs to update table

                     DBCompareColExpr cmpExpr = (DBCompareColExpr) cmp;

-                    DBColumn col = cmpExpr.getColumn().getUpdateColumn();

+                    DBColumn col = cmpExpr.getColumnExpr().getUpdateColumn();

                     if (col!=null && col.getRowSet() == table)

                     {	// add the constraint

                     	if (cmpExpr.getValue() instanceof DBCmdParam)

                     	{	// Create a new command param

-                    		DBColumnExpr colExpr = cmpExpr.getColumn();

+                    		DBColumnExpr colExpr = cmpExpr.getColumnExpr();

                     		DBCmdParam param =(DBCmdParam)cmpExpr.getValue(); 

                     		DBCmdParam value = upd.addParam(colExpr, param.getValue());

                     		cmp = new DBCompareColExpr(colExpr, cmpExpr.getCmpOperator(), value);

diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAbstractFuncExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAbstractFuncExpr.java
index b2cf4a5..5ff1cd4 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAbstractFuncExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBAbstractFuncExpr.java
@@ -26,6 +26,7 @@
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.exceptions.DatabaseNotOpenException;
 import org.apache.empire.dbms.DBMSHandler;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.xml.XMLUtil;
@@ -72,10 +73,15 @@
      * returns the Database dbms or null if the Expression is not attached to an open database<BR>
      * This function is intended for convenience only.
      */
-    protected final DBMSHandler getDbms()
+    protected DBMSHandler getDbms()
     {
-        DBDatabase db = getDatabase();
-        return (db!=null) ? db.getDbms() : null;
+        DBDatabase db = expr.getDatabase();
+        if (db==null)
+            throw new InvalidArgumentException("expr", expr);
+        DBMSHandler dbms = db.getDbms();
+        if (dbms==null)
+            throw new DatabaseNotOpenException(db);
+        return dbms;
     }
 
     /**
@@ -227,7 +233,7 @@
                     ph += template.substring(idx, end+1);
                     
                 } else {
-                    log.warn("No placeholder found in template {} for paramter {}", template, i);
+                    log.info("No placeholder found in template {} for paramter {}", template, i);
                     continue;
                 }
                 // get param and replace      
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBCmdResultExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBCmdResultExpr.java
new file mode 100644
index 0000000..862ee17
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBCmdResultExpr.java
@@ -0,0 +1,118 @@
+/*
+ * 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.empire.db.expr.column;
+
+import java.util.Set;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBCommandExpr;
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.exceptions.InvalidArgumentException;
+import org.apache.empire.xml.XMLUtil;
+import org.w3c.dom.Element;
+
+public class DBCmdResultExpr extends DBColumnExpr
+{
+    private final DBCommandExpr cmdExpr;
+
+    private final DBColumnExpr result;
+    
+    public DBCmdResultExpr(DBCommandExpr cmdExpr)
+    {
+        this.cmdExpr = cmdExpr;
+        // get the result column
+        DBColumnExpr[] sel = cmdExpr.getSelectExprList();
+        if (sel.length!=1)
+            throw new InvalidArgumentException("cmdExpr", cmdExpr);
+        // result
+        this.result = sel[0];
+    }
+
+    @Override
+    public <T extends DBDatabase> T getDatabase()
+    {
+        return cmdExpr.getDatabase();
+    }
+
+    @Override
+    public Class<Enum<?>> getEnumType()
+    {
+        return result.getEnumType();
+    }
+
+    @Override
+    public DataType getDataType()
+    {
+        return result.getDataType();
+    }
+
+    @Override
+    public String getName()
+    {
+        return "SEL_"+result.getName();
+    }
+
+    @Override
+    public boolean isAggregate()
+    {
+        /* does not need a GROUP_BY */ 
+        return false;
+    }
+
+    @Override
+    public DBColumn getSourceColumn()
+    {
+        return null;
+    }
+
+    @Override
+    public DBColumn getUpdateColumn()
+    {
+        return null;
+    }
+
+    @Override
+    public void addReferencedColumns(Set<DBColumn> list)
+    {
+        /* NONE */
+    }
+
+    @Override
+    public void addSQL(StringBuilder buf, long context)
+    {
+        // simply forward
+        cmdExpr.addSQL(buf, context);
+    }
+
+    @Override
+    public Element addXml(Element parent, long flags)
+    {
+        // Add a column expression for this function
+        Element elem = XMLUtil.addElement(parent, "column");
+        elem.setAttribute("name", getName());
+        elem.setAttribute("function", "cmd");
+        elem.setAttribute("dataType", getDataType().name());
+        elem.setAttribute("aggregate", "true");
+        // Done
+        return elem;
+    }
+    
+}
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBFuncExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBFuncExpr.java
index 0bbd93c..4feaf9d 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/column/DBFuncExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/column/DBFuncExpr.java
@@ -20,12 +20,14 @@
 
 import java.util.Set;
 
+import org.apache.empire.commons.StringUtils;
 // Java
 import org.apache.empire.data.DataType;
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBColumnExpr;
 import org.apache.empire.db.DBExpr;
 import org.apache.empire.dbms.DBSqlPhrase;
+import org.apache.empire.exceptions.NotSupportedException;
 
 
 /**
@@ -46,7 +48,7 @@
 
     protected final DBSqlPhrase  phrase;
     protected final Object[]     params;
-    protected String             template;
+    protected final String       template;
 
     /**
      * Constructs a new DBFuncExpr object set the specified parameters to this object.
@@ -58,8 +60,6 @@
      * @param expr the DBColumnExpr object
      * @param phrase the SQL-phrase
      * @param params an array of params which will be replaced in the template
-     * @param updateColumn optional update column if any. This parameter may be null
-     * @param isAggregate indicates whether the function is an aggregate function (sum, min, max, avg, ...)
      * @param dataType indicates the data type of the function result 
      */
     public DBFuncExpr(DBColumnExpr expr, DBSqlPhrase phrase, Object[] params, DataType dataType)
@@ -68,7 +68,9 @@
         // Set Phrase and Params
         this.phrase = phrase;
         this.params = params;
-        this.template = null;
+        this.template = getDbms().getSQLPhrase(phrase);
+        if (StringUtils.isEmpty(template))
+            throw new NotSupportedException(getDbms(), phrase.name());
         // check
         if (phrase==DBSqlPhrase.SQL_FUNC_COALESCE)
             log.warn("DBFuncExpr should not be used for SQL_FUNC_COALESCE. Use DBCoalesceExpr instead.");
@@ -102,11 +104,7 @@
         // Get the template
         if (phrase!=null)
         {   // from phrase
-            int end = phrase.name().lastIndexOf('_');
-            if (end>0)
-                return phrase.name().substring(end+1);
-            // the phrase
-            return phrase.name();
+            return phrase.getFuncName();
         }
         // Get the first word
         if (template!=null)
@@ -157,12 +155,7 @@
      */
     @Override
     public void addSQL(StringBuilder sql, long context)
-    {
-        // Get the template
-        if (template==null)
-            template = getDbms().getSQLPhrase(phrase);
-        // Add SQL
+    {        // Add SQL
         super.addSQL(sql, template, params, context);
     }
-    
 }
\ No newline at end of file
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareAndOrExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareAndOrExpr.java
index 10a8c78..e052054 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareAndOrExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareAndOrExpr.java
@@ -169,12 +169,12 @@
     @Override
     public boolean isMutuallyExclusive(DBCompareExpr other)
     {
-        if (other instanceof Unwrappable<?>)
-        {
+        if ((other instanceof Unwrappable<?>) && ((Unwrappable<?>)other).isWrapper())
+        {   // unwrap
             other = ((Unwrappable<DBCompareExpr>)other).unwrap();
         }
     	if (other instanceof DBCompareAndOrExpr)
-    	{
+    	{   // check other
     		DBCompareAndOrExpr otherExpr = (DBCompareAndOrExpr)other;
             if (left .isMutuallyExclusive(otherExpr.left) &&
                 right.isMutuallyExclusive(otherExpr.right))
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareColExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareColExpr.java
index 8f5816e..39c5ccf 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareColExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareColExpr.java
@@ -80,7 +80,7 @@
      * Gets the DBColumnExpr object 
      * @return the DBColumnExpr object 
      */
-    public DBColumnExpr getColumn()
+    public DBColumnExpr getColumnExpr()
     {
         return expr;
     }
@@ -301,7 +301,7 @@
                 texpr = texpr.unwrap();
             // other
             DBCompareColExpr o = (DBCompareColExpr)other;
-            DBColumnExpr oexpr = o.getColumn();
+            DBColumnExpr oexpr = o.getColumnExpr();
             if (oexpr.isWrapper())
                 oexpr = oexpr.unwrap();
     		// Compare
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareNotExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareNotExpr.java
index 4d19867..04ddfed 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareNotExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/compare/DBCompareNotExpr.java
@@ -132,12 +132,12 @@
     @Override
     public boolean isMutuallyExclusive(DBCompareExpr other)
     {
-        if (other instanceof Unwrappable<?>)
-        {
+        if ((other instanceof Unwrappable<?>) && ((Unwrappable<?>)other).isWrapper())
+        {   // unwrap
             other = ((Unwrappable<DBCompareExpr>)other).unwrap();
         }
         if (other instanceof DBCompareNotExpr)
-        {
+        {   // compare
             DBCompareNotExpr otherNot = (DBCompareNotExpr)other;
             return expr.isMutuallyExclusive(otherNot.expr); 
         }
diff --git a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
index 97c91d1..3cb7a03 100644
--- a/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/expr/join/DBCompareJoinExpr.java
@@ -58,7 +58,7 @@
             return findFirstColumn(((DBCompareNotExpr)expr).getExpr());
         // Get Column Expr
         if (expr instanceof DBCompareColExpr)
-            return ((DBCompareColExpr)expr).getColumn();
+            return ((DBCompareColExpr)expr).getColumnExpr();
         // Error
         log.error("Unknown class found for building a valid JOIN Expression");
         return null;
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java b/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
index b2d2c21..4f7f9e2 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/DBSqlPhrase.java
@@ -34,7 +34,7 @@
 
     // functions
     SQL_FUNC_COALESCE       ("coalesce(?, {0})"),       // Oracle: nvl(?, {0})
-    SQL_FUNC_SUBSTRING      ("substring(?,{0})"),       // Oracle: substr(?,{0})
+    SQL_FUNC_SUBSTRING      ("substring(?, {0})"),      // Oracle: substr(?,{0})
     SQL_FUNC_SUBSTRINGEX    ("substring(?, {0}, {1})"), // Oracle: substr(?,{0},{1})
     SQL_FUNC_REPLACE        ("replace(?, {0}, {1})"),   // Oracle: replace(?,{0},{1})
     SQL_FUNC_REVERSE        ("reverse(?)"),             // Oracle: reverse(?) 
@@ -55,7 +55,7 @@
     SQL_FUNC_TRUNC          ("trunc(?, {0})"),
     SQL_FUNC_FLOOR          ("floor(?)"),
     SQL_FUNC_CEILING        ("ceiling(?)"),             // Oracle: ceil(?)
-    SQL_FUNC_MODULO         ("((?) % {0})"),            // Oracle: mod(?)
+    SQL_FUNC_MOD            ("((?) % {0})"),            // Oracle: mod(?)
     SQL_FUNC_FORMAT         ("format(?, {0:VARCHAR})"), // Oracle: TO_CHAR(?, {0:VARCHAR})
 
     // Date
@@ -68,7 +68,7 @@
     SQL_FUNC_MAX            ("max(?)", true),
     SQL_FUNC_MIN            ("min(?)", true),
     SQL_FUNC_AVG            ("avg(?)", true),
-    SQL_FUNC_STRAGG         ("string_agg(?,{0})", true), // string_agg, LISTAGG
+    SQL_FUNC_STRAGG         (null),                     // Not supported by default
 
     // Decode
     SQL_FUNC_DECODE         ("case ? {0} end"),         // Oracle: decode(? {0})
@@ -76,6 +76,11 @@
     SQL_FUNC_DECODE_PART    ("when {0} then {1}"),      // Oracle: {0}, {1}
     SQL_FUNC_DECODE_ELSE    ("else {0}");               // Oracle: {0}
 
+    
+    private static final String PREFIX_SQL = "SQL_";
+    private static final String PREFIX_FUNC = "FUNC_";
+    
+    private final String funcName;
     private final String sqlDefault;
     private final boolean aggregate;
     
@@ -83,6 +88,13 @@
     {
         this.sqlDefault = sqlDefault;
         this.aggregate = aggregate;
+        // get the function name
+        String name = name();
+        if (name.startsWith(PREFIX_SQL))
+            name = name.substring(PREFIX_SQL.length());
+        if (name.startsWith(PREFIX_FUNC))
+            name = name.substring(PREFIX_FUNC.length());
+        this.funcName = name;
     }
     
     private DBSqlPhrase(String sqlDefault)
@@ -90,6 +102,11 @@
         this(sqlDefault, false);
     }
 
+    public String getFuncName()
+    {
+        return funcName;
+    }
+
     public String getSqlDefault()
     {
         return sqlDefault;
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/derby/DBMSHandlerDerby.java b/empire-db/src/main/java/org/apache/empire/dbms/derby/DBMSHandlerDerby.java
index ad099f7..ae37160 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/derby/DBMSHandlerDerby.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/derby/DBMSHandlerDerby.java
@@ -197,7 +197,7 @@
             case SQL_FUNC_TRUNC:              return "truncate(?,{0})";
             case SQL_FUNC_CEILING:            return "ceiling(?)";
             case SQL_FUNC_FLOOR:              return "floor(?)";
-            case SQL_FUNC_MODULO:             return "mod(?,{0})";
+            case SQL_FUNC_MOD:                return "mod(?,{0})";
             case SQL_FUNC_FORMAT:             return "format(?, {0:VARCHAR})";
             // Date
             case SQL_FUNC_DAY:                return "day(?)";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/h2/DBMSHandlerH2.java b/empire-db/src/main/java/org/apache/empire/dbms/h2/DBMSHandlerH2.java
index f09a6f3..79fed13 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/h2/DBMSHandlerH2.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/h2/DBMSHandlerH2.java
@@ -272,7 +272,7 @@
             case SQL_FUNC_TRUNC:              return "truncate(?,{0})";
             case SQL_FUNC_CEILING:            return "ceiling(?)";
             case SQL_FUNC_FLOOR:              return "floor(?)";
-            case SQL_FUNC_MODULO:             return "mod(?,{0})";
+            case SQL_FUNC_MOD:                return "mod(?,{0})";
             case SQL_FUNC_FORMAT:             return "format(?, {0:VARCHAR})";
             // Date
             case SQL_FUNC_DAY:                return "day(?)";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
index aafefc9..3160a23 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/hsql/DBMSHandlerHSql.java
@@ -147,7 +147,7 @@
             case SQL_FUNC_TRUNC:        return "truncate(?,{0})";
             case SQL_FUNC_CEILING:      return "ceiling(?)";
             case SQL_FUNC_FLOOR:        return "floor(?)";
-            case SQL_FUNC_MODULO:       return "mod(?,{0})";
+            case SQL_FUNC_MOD:          return "mod(?,{0})";
             case SQL_FUNC_FORMAT:       return "TO_CHAR(?, {0:VARCHAR})";
             // Date
             case SQL_FUNC_DAY:          return "day(?)";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/mysql/DBMSHandlerMySQL.java b/empire-db/src/main/java/org/apache/empire/dbms/mysql/DBMSHandlerMySQL.java
index 6dde1af..553beb1 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/mysql/DBMSHandlerMySQL.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/mysql/DBMSHandlerMySQL.java
@@ -1028,7 +1028,7 @@
             case SQL_FUNC_TRUNC:              return "truncate(?,{0})";
             case SQL_FUNC_CEILING:            return "ceiling(?)";
             case SQL_FUNC_FLOOR:              return "floor(?)";
-            case SQL_FUNC_MODULO:             return "mod(?,{0})";
+            case SQL_FUNC_MOD:                return "mod(?,{0})";
             case SQL_FUNC_FORMAT:             return "format(?, {0:INTEGER})"; /* TODO: supports only decimal places. Add support for a format string */
             // Date
             case SQL_FUNC_DAY:                return "day(?)";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBMSHandlerOracle.java b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBMSHandlerOracle.java
index 43f8ed8..2fc2d0c 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBMSHandlerOracle.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/oracle/DBMSHandlerOracle.java
@@ -213,7 +213,7 @@
             case SQL_FUNC_TRUNC:                return "trunc(?,{0})";
             case SQL_FUNC_CEILING:              return "ceil(?)";
             case SQL_FUNC_FLOOR:                return "floor(?)";
-            case SQL_FUNC_MODULO:               return "mod(?,{0})";
+            case SQL_FUNC_MOD:                  return "mod(?,{0})";
             case SQL_FUNC_FORMAT:               return "TO_CHAR(?, {0:VARCHAR})";
             // Date
             case SQL_FUNC_DAY:                  return oracle8Compatibilty ? "to_number(to_char(?,'DD'))"   : "extract(day from ?)";
@@ -224,7 +224,7 @@
             case SQL_FUNC_MAX:                  return "max(?)";
             case SQL_FUNC_MIN:                  return "min(?)";
             case SQL_FUNC_AVG:                  return "avg(?)";
-            case SQL_FUNC_STRAGG:               return "listagg(? {0})";
+            case SQL_FUNC_STRAGG:               return "listagg(? {0}) WITHIN GROUP (ORDER BY {1})";
             // Others
             case SQL_FUNC_DECODE:               return "decode(? {0})";
             case SQL_FUNC_DECODE_SEP:           return ",";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBCommandPostgres.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBCommandPostgres.java
new file mode 100644
index 0000000..df1f45e
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBCommandPostgres.java
@@ -0,0 +1,157 @@
+/*
+ * 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.empire.dbms.postgresql;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBCommand;
+import org.apache.empire.db.DBRowSet;
+import org.apache.empire.db.exceptions.NoPrimaryKeyException;
+import org.apache.empire.db.expr.column.DBValueExpr;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+
+/**
+ * Defines the PostgreSQL command type.
+ */ 
+public class DBCommandPostgres extends DBCommand
+{
+    // *Deprecated* private static final long serialVersionUID = 1L;
+  
+    protected int limit = -1;
+    protected int skip  = -1;
+    
+    public DBCommandPostgres(boolean autoPrepareStmt)
+    {
+        super(autoPrepareStmt);
+    }
+    
+    public DBColumnExpr funcAge(DBColumnExpr expr)
+    {
+        return new PostgresFuncExpr(expr, PostgresSqlPhrase.AGE, null, DataType.INTEGER);
+    }
+    
+    public DBColumnExpr funcAge(DBColumnExpr expr1, DBColumnExpr expr2)
+    {
+        return new PostgresFuncExpr(expr1, PostgresSqlPhrase.AGE_TWO, new Object[] { expr2 }, DataType.INTEGER);
+    }
+    
+    public DBColumnExpr funcExtract(PostgresExtractField field, DBColumnExpr expr)
+    {
+        DBValueExpr fieldExpr = new DBValueExpr(expr.getDatabase(), field.name(), DataType.UNKNOWN);
+        return new PostgresFuncExpr(expr, PostgresSqlPhrase.EXTRACT, new Object[] { fieldExpr }, DataType.INTEGER);
+    }
+    
+    public DBColumnExpr funcToTsquery(DBColumnExpr expr)
+    {
+        return new PostgresFuncExpr(expr, PostgresSqlPhrase.TO_TSQUERY, null, DataType.UNKNOWN);
+    }
+    
+    public DBColumnExpr funcToTsvector(DBColumnExpr expr)
+    {
+        return new PostgresFuncExpr(expr, PostgresSqlPhrase.TO_TSVECTOR, null, DataType.UNKNOWN);
+    }
+    
+    public DBColumnExpr funcPlaintoTsquery(DBColumnExpr expr)
+    {
+        return new PostgresFuncExpr(expr, PostgresSqlPhrase.PLAINTO_TSQUERY, null, DataType.UNKNOWN);
+    }
+    
+    public DBColumnExpr funcBoolAnd(DBCompareExpr cmpExpr)
+    {
+        return new PostgresBoolAndOrExpr(cmpExpr, false);
+    }
+    
+    public DBColumnExpr funcBoolOr(DBCompareExpr cmpExpr)
+    {
+        return new PostgresBoolAndOrExpr(cmpExpr, true);
+    }
+    
+    @Override
+    public DBCommand limitRows(int numRows)
+    {
+        limit = numRows;
+        return this;
+    }
+
+    @Override
+    public DBCommand skipRows(int numRows)
+    {
+        skip = numRows;
+        return this;
+    }
+     
+    @Override
+    public void clearLimit()
+    {
+        limit = -1;
+        skip  = -1;
+    }
+    
+    @Override
+    public void getSelect(StringBuilder buf)
+    {   // call base class
+        super.getSelect(buf);
+        // add limit and offset
+        if (limit>=0)
+        {   buf.append("\r\nLIMIT ");
+            buf.append(String.valueOf(limit));
+            // Offset
+            if (skip>=0) 
+            {   buf.append(" OFFSET ");
+                buf.append(String.valueOf(skip));
+            }    
+        }
+    }
+    
+    @Override
+    protected void addUpdateWithJoins(StringBuilder buf, DBRowSet table)
+    {
+        DBColumn[] keyColumns = table.getKeyColumns();
+        if (keyColumns==null || keyColumns.length==0)
+            throw new NoPrimaryKeyException(table);
+        // Join Update
+        table.addSQL(buf, CTX_NAME);
+        buf.append(" t0");
+        long context = CTX_DEFAULT;
+        // Set Expressions
+        buf.append("\r\nSET ");
+        addListExpr(buf, set, context, ", ");
+        // From clause
+        addFrom(buf);
+        // Add Where
+        buf.append("\r\nWHERE");
+        // key columns
+        for (DBColumn col : keyColumns)
+        {   // compare 
+            buf.append(" t0.");
+            col.addSQL(buf, CTX_NAME);
+            buf.append("=");
+            buf.append(table.getAlias());
+            buf.append(".");
+            col.addSQL(buf, CTX_NAME);
+        }
+        // more constraints
+        if (where!=null && !where.isEmpty())
+        {   // add where expression
+            buf.append("\r\n  AND ");
+            addListExpr(buf, where, context, " AND ");
+        }
+    }
+}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBMSHandlerPostgreSQL.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBMSHandlerPostgreSQL.java
index d798160..f731708 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBMSHandlerPostgreSQL.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/DBMSHandlerPostgreSQL.java
@@ -26,18 +26,14 @@
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.DataType;
-import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBColumnExpr;
-import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBDDLGenerator;
 import org.apache.empire.db.DBDDLGenerator.DDLActionType;
 import org.apache.empire.db.DBDatabase;
 import org.apache.empire.db.DBObject;
-import org.apache.empire.db.DBRowSet;
 import org.apache.empire.db.DBSQLScript;
 import org.apache.empire.db.DBTableColumn;
 import org.apache.empire.db.exceptions.EmpireSQLException;
-import org.apache.empire.db.exceptions.NoPrimaryKeyException;
 import org.apache.empire.db.exceptions.QueryNoResultException;
 import org.apache.empire.db.expr.column.DBValueExpr;
 import org.apache.empire.dbms.DBMSFeature;
@@ -79,93 +75,6 @@
         "END\n" +
         "$$ LANGUAGE plpgsql IMMUTABLE RETURNS NULL ON NULL INPUT";    
     
-    /**
-     * Defines the PostgreSQL command type.
-     */ 
-    public static class DBCommandPostreSQL extends DBCommand
-    {
-        // *Deprecated* private static final long serialVersionUID = 1L;
-      
-        protected int limit = -1;
-        protected int skip  = -1;
-        
-        public DBCommandPostreSQL(boolean autoPrepareStmt)
-        {
-            super(autoPrepareStmt);
-        }
-        
-        @Override
-        public DBCommand limitRows(int numRows)
-        {
-            limit = numRows;
-            return this;
-        }
-
-        @Override
-        public DBCommand skipRows(int numRows)
-        {
-            skip = numRows;
-            return this;
-        }
-         
-        @Override
-        public void clearLimit()
-        {
-            limit = -1;
-            skip  = -1;
-        }
-        
-        @Override
-        public void getSelect(StringBuilder buf)
-        {   // call base class
-            super.getSelect(buf);
-            // add limit and offset
-            if (limit>=0)
-            {   buf.append("\r\nLIMIT ");
-                buf.append(String.valueOf(limit));
-                // Offset
-                if (skip>=0) 
-                {   buf.append(" OFFSET ");
-                    buf.append(String.valueOf(skip));
-                }    
-            }
-        }
-        
-        @Override
-        protected void addUpdateWithJoins(StringBuilder buf, DBRowSet table)
-        {
-            DBColumn[] keyColumns = table.getKeyColumns();
-            if (keyColumns==null || keyColumns.length==0)
-                throw new NoPrimaryKeyException(table);
-            // Join Update
-            table.addSQL(buf, CTX_NAME);
-            buf.append(" t0");
-            long context = CTX_DEFAULT;
-            // Set Expressions
-            buf.append("\r\nSET ");
-            addListExpr(buf, set, context, ", ");
-            // From clause
-            addFrom(buf);
-            // Add Where
-            buf.append("\r\nWHERE");
-            // key columns
-            for (DBColumn col : keyColumns)
-            {   // compare 
-                buf.append(" t0.");
-                col.addSQL(buf, CTX_NAME);
-                buf.append("=");
-                buf.append(table.getAlias());
-                buf.append(".");
-                col.addSQL(buf, CTX_NAME);
-            }
-            // more constraints
-            if (where!=null && !where.isEmpty())
-            {   // add where expression
-                buf.append("\r\n  AND ");
-                addListExpr(buf, where, context, " AND ");
-            }
-        }
-    }
     
     private String databaseName;
 
@@ -331,10 +240,9 @@
      * @return the new DBCommandPostgreSQL object
      */
     @Override
-    public DBCommand createCommand(boolean autoPrepareStmt)
-    {
-        // create command object
-        return new DBCommandPostreSQL(autoPrepareStmt);
+    public DBCommandPostgres createCommand(boolean autoPrepareStmt)
+    {   // create command object
+        return new DBCommandPostgres(autoPrepareStmt);
     }
 
     /**
@@ -412,7 +320,7 @@
             case SQL_FUNC_TRUNC:              return "truncate(?,{0})";
             case SQL_FUNC_CEILING:            return "ceiling(?)";
             case SQL_FUNC_FLOOR:              return "floor(?)";
-            case SQL_FUNC_MODULO:             return "mod(?,{0})";
+            case SQL_FUNC_MOD:                return "mod(?,{0})";
             case SQL_FUNC_FORMAT:             return "format({0:VARCHAR}, ?)";
             // Date
 			case SQL_FUNC_DAY:                return "extract(day from ?)";
@@ -423,6 +331,7 @@
             case SQL_FUNC_MAX:                return "max(?)";
             case SQL_FUNC_MIN:                return "min(?)";
             case SQL_FUNC_AVG:                return "avg(?)";
+            case SQL_FUNC_STRAGG:             return "STRING_AGG(DISTINCT ? {0} ORDER BY {1})";
             // Others
             case SQL_FUNC_DECODE:             return "case ? {0} end";
             case SQL_FUNC_DECODE_SEP:         return " ";
@@ -525,7 +434,7 @@
     public void getDDLScript(DDLActionType type, DBObject dbo, DBSQLScript script)
     {
         if (ddlGenerator==null)
-            ddlGenerator = new PostgreSQLDDLGenerator(this);
+            ddlGenerator = new PostgresDDLGenerator(this);
         // forward request
         ddlGenerator.getDDLScript(type, dbo, script); 
     }
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresBoolAndOrExpr.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresBoolAndOrExpr.java
new file mode 100644
index 0000000..db59da9
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresBoolAndOrExpr.java
@@ -0,0 +1,148 @@
+/*
+ * 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.empire.dbms.postgresql;
+
+import java.util.Set;
+
+import org.apache.empire.commons.Unwrappable;
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBDatabase;
+import org.apache.empire.db.expr.compare.DBCompareAndOrExpr;
+import org.apache.empire.db.expr.compare.DBCompareColExpr;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.db.expr.compare.DBCompareNotExpr;
+import org.apache.empire.xml.XMLUtil;
+import org.w3c.dom.Element;
+
+public class PostgresBoolAndOrExpr extends DBColumnExpr
+{
+    private static final String BOOL_AND         = "BOOL_AND";
+    private static final String BOOL_OR          = "BOOL_OR";
+
+    private final DBCompareExpr cmpExpr;
+    private final boolean       or;
+    private String name;
+
+    public PostgresBoolAndOrExpr(DBCompareExpr cmpExpr, boolean or)
+    {
+        this.cmpExpr = cmpExpr;
+        this.or = or;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public DBDatabase getDatabase()
+    {
+        return cmpExpr.getDatabase();
+    }
+
+    @Override
+    public DataType getDataType()
+    {
+        return DataType.BOOL;
+    }
+
+    @Override
+    public Class<Enum<?>> getEnumType()
+    {
+        return null;
+    }
+
+    @Override
+    public DBColumn getSourceColumn()
+    {
+        return null;
+    }
+
+    @Override
+    public String getName()
+    {
+        if (name==null)
+        {   // Build name
+            StringBuilder buf = new StringBuilder();
+            appendName(buf, this.cmpExpr);
+            buf.append("_");
+            buf.append(or ? BOOL_OR : BOOL_AND);
+            name = buf.toString();
+        }
+        return name;
+    }
+
+    @Override
+    public boolean isAggregate()
+    {
+        return true;
+    }
+
+    @Override
+    public DBColumn getUpdateColumn()
+    {
+        return null;
+    }
+
+    @Override
+    public void addReferencedColumns(Set<DBColumn> list)
+    {
+        cmpExpr.addReferencedColumns(list);
+    }
+
+    @Override
+    public void addSQL(StringBuilder buf, long context)
+    {
+
+        buf.append(or ? BOOL_OR : BOOL_AND);
+        buf.append("(");
+        cmpExpr.addSQL(buf, context);
+        buf.append(")");
+    }
+
+    @Override
+    public Element addXml(Element parent, long flags)
+    {
+        // Add a column expression for this function
+        Element elem = XMLUtil.addElement(parent, "column");
+        elem.setAttribute("name", getName());
+        elem.setAttribute("function", (or ? BOOL_OR : BOOL_AND));
+        elem.setAttribute("dataType", getDataType().name());
+        elem.setAttribute("aggregate", "true");
+        return elem;
+    }
+    
+    @SuppressWarnings("unchecked")
+    protected void appendName(StringBuilder buf, DBCompareExpr expr)
+    {
+        if ((expr instanceof Unwrappable<?>) && ((Unwrappable<?>)expr).isWrapper())
+            appendName(buf, ((Unwrappable<DBCompareExpr>)expr).unwrap());
+        else if (expr instanceof DBCompareNotExpr)
+            appendName(buf, ((DBCompareNotExpr)expr).getExpr());
+        else if (expr instanceof DBCompareAndOrExpr) {
+            appendName(buf, ((DBCompareAndOrExpr)expr).getLeft());
+            appendName(buf, ((DBCompareAndOrExpr)expr).getRight());
+        }
+        else if (expr instanceof DBCompareColExpr) {
+            DBColumnExpr colExpr = ((DBCompareColExpr)expr).getColumnExpr();
+            if (buf.length()>0)
+                buf.append("_");
+            buf.append(colExpr.getName());
+        }
+    }
+
+}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgreSQLDDLGenerator.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresDDLGenerator.java
similarity index 96%
rename from empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgreSQLDDLGenerator.java
rename to empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresDDLGenerator.java
index 25a686f..edfda3a 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgreSQLDDLGenerator.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresDDLGenerator.java
@@ -27,9 +27,9 @@
 import org.apache.empire.db.DBTable;

 import org.apache.empire.db.DBTableColumn;

 

-public class PostgreSQLDDLGenerator extends DBDDLGenerator<DBMSHandlerPostgreSQL>

+public class PostgresDDLGenerator extends DBDDLGenerator<DBMSHandlerPostgreSQL>

 {

-    public PostgreSQLDDLGenerator(DBMSHandlerPostgreSQL dbms)

+    public PostgresDDLGenerator(DBMSHandlerPostgreSQL dbms)

     {

         super(dbms);

         // set Oracle specific data types

diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresExtractField.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresExtractField.java
new file mode 100644
index 0000000..54059f0
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresExtractField.java
@@ -0,0 +1,44 @@
+/*
+ * 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.empire.dbms.postgresql;
+
+public enum PostgresExtractField
+{
+    CENTURY,
+    DAY,
+    DECADE,
+    DOW,
+    DOY,
+    EPOCH,
+    HOUR,
+    ISODOW,
+    ISOYEAR,
+    MICROSECONDS,
+    MILLENNIUM,
+    MILLISECONDS,
+    MINUTE,
+    MONTH,
+    QUARTER,
+    SECOND,
+    TIMEZONE,
+    TIMEZONE_HOUR,
+    TIMEZONE_MINUTE,
+    WEEK,
+    YEAR;
+}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresFuncExpr.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresFuncExpr.java
new file mode 100644
index 0000000..7522247
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresFuncExpr.java
@@ -0,0 +1,86 @@
+/*
+ * 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.empire.dbms.postgresql;
+
+import java.util.Set;
+
+import org.apache.empire.data.DataType;
+import org.apache.empire.db.DBColumn;
+import org.apache.empire.db.DBColumnExpr;
+import org.apache.empire.db.DBExpr;
+import org.apache.empire.db.expr.column.DBAbstractFuncExpr;
+
+public class PostgresFuncExpr extends DBAbstractFuncExpr
+{
+    // *Deprecated* private static final long serialVersionUID = 1L;
+
+    protected final PostgresSqlPhrase  phrase;
+    protected final Object[]     params;
+
+    /**
+     * @param expr the DBColumnExpr object
+     * @param phrase the SQL-phrase
+     * @param params an array of params which will be replaced in the template
+     * @param dataType indicates the data type of the function result 
+     */
+    public PostgresFuncExpr(DBColumnExpr expr, PostgresSqlPhrase phrase, Object[] params, DataType dataType)
+    {
+        super(expr, phrase.isAggregate(), dataType);
+        // Set Phrase and Params
+        this.phrase = phrase;
+        this.params = params;
+    }
+    
+    @Override
+    protected String getFunctionName()
+    {
+        return phrase.name();
+    }
+
+    /**
+     * @see org.apache.empire.db.DBExpr#addReferencedColumns(Set)
+     */
+    @Override
+    public void addReferencedColumns(Set<DBColumn> list)
+    {
+        super.addReferencedColumns(list);
+        if (this.params==null)
+            return;
+        // Check params
+        for (int i=0; i<this.params.length; i++)
+        {   // add referenced columns
+            if (params[i] instanceof DBExpr)
+               ((DBExpr)params[i]).addReferencedColumns(list);
+        }
+    }
+
+    /**
+     * Creates the SQL-Command adds a function to the SQL-Command.
+     * 
+     * @param sql the SQL-Command
+     * @param context the current SQL-Command context
+     */
+    @Override
+    public void addSQL(StringBuilder sql, long context)
+    {
+        // Add SQL
+        super.addSQL(sql, phrase.getSQL(), params, context);
+    }
+    
+}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresSqlPhrase.java b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresSqlPhrase.java
new file mode 100644
index 0000000..f9c70c0
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/dbms/postgresql/PostgresSqlPhrase.java
@@ -0,0 +1,58 @@
+/*
+ * 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.empire.dbms.postgresql;
+
+/**
+ * Enum for all SQL phrases that may be supplied by the dbms
+ * @author rainer
+ */
+public enum PostgresSqlPhrase
+{
+    // functions
+    AGE             ("AGE(?)"),
+    AGE_TWO         ("AGE(?, {0})"),
+    EXTRACT         ("EXTRACT({0} from ?)"),
+    TO_TSQUERY      ("to_tsquery(?)"),
+    TO_TSVECTOR     ("to_tsvector(?)"),
+    PLAINTO_TSQUERY ("plainto_tsquery(?)");
+
+    private final String functionSQL;
+    private final boolean aggregate;
+    
+    private PostgresSqlPhrase(String phrase, boolean aggregate)
+    {
+        this.functionSQL = phrase;
+        this.aggregate = aggregate;
+    }
+    
+    private PostgresSqlPhrase(String sqlDefault)
+    {
+        this(sqlDefault, false);
+    }
+
+    public String getSQL()
+    {
+        return functionSQL;
+    }
+
+    public boolean isAggregate()
+    {
+        return aggregate;
+    }
+}
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/sqlite/DBMSHandlerSQLite.java b/empire-db/src/main/java/org/apache/empire/dbms/sqlite/DBMSHandlerSQLite.java
index 964605d..932eac8 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/sqlite/DBMSHandlerSQLite.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/sqlite/DBMSHandlerSQLite.java
@@ -350,7 +350,7 @@
             case SQL_FUNC_TRUNC:            return "truncate(?,{0})";
             case SQL_FUNC_CEILING:          return "ceiling(?)";
             case SQL_FUNC_FLOOR:            return "floor(?)";
-            case SQL_FUNC_MODULO:           return "mod(?,{0})";
+            case SQL_FUNC_MOD:              return "mod(?,{0})";
             case SQL_FUNC_FORMAT:           return "printf({0:VARCHAR}, ?)";
             // Date
             case SQL_FUNC_DAY:              return "day(?)";
diff --git a/empire-db/src/main/java/org/apache/empire/dbms/sqlserver/DBMSHandlerMSSQL.java b/empire-db/src/main/java/org/apache/empire/dbms/sqlserver/DBMSHandlerMSSQL.java
index 4e08b35..11f4337 100644
--- a/empire-db/src/main/java/org/apache/empire/dbms/sqlserver/DBMSHandlerMSSQL.java
+++ b/empire-db/src/main/java/org/apache/empire/dbms/sqlserver/DBMSHandlerMSSQL.java
@@ -361,7 +361,7 @@
             case SQL_FUNC_TRUNC:              return "trunc(?,{0})";
             case SQL_FUNC_CEILING:            return "ceiling(?)";
             case SQL_FUNC_FLOOR:              return "floor(?)";
-            case SQL_FUNC_MODULO:             return "((?) % {0})";
+            case SQL_FUNC_MOD:                return "((?) % {0})";
             case SQL_FUNC_FORMAT:             return "format(?, {0:VARCHAR})";
             // Date
             case SQL_FUNC_DAY:                return "day(?)";
@@ -372,6 +372,7 @@
             case SQL_FUNC_MAX:                return "max(?)";
             case SQL_FUNC_MIN:                return "min(?)";
             case SQL_FUNC_AVG:                return "avg(?)";
+            case SQL_FUNC_STRAGG:             return "string_agg(?,{0}) WITHIN GROUP (ORDER BY {1})";
             // Others
             case SQL_FUNC_DECODE:             return "case ? {0} end";
             case SQL_FUNC_DECODE_SEP:         return " ";