Index: DefaultExpressionBuilder.java
===================================================================
--- DefaultExpressionBuilder.java	(revision 44197)
+++ DefaultExpressionBuilder.java	(revision 44198)
@@ -2,165 +2,73 @@
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import org.apache.commons.lang3.ObjectUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.cresques.cts.IProjection;
+import org.gvsig.expressionevaluator.Code;
 import org.gvsig.fmap.geom.Geometry;
 import org.gvsig.fmap.geom.primitive.Envelope;
 
 import org.gvsig.expressionevaluator.ExpressionBuilder;
+import static org.gvsig.expressionevaluator.ExpressionBuilder.EMPTY_FORMATTER;
+import org.gvsig.expressionevaluator.ExpressionUtils;
+import org.gvsig.expressionevaluator.Formatter;
+import org.gvsig.fmap.geom.GeometryUtils;
 
-@SuppressWarnings({"UseSpecificCatch","OverridableMethodCallInConstructor"})
+@SuppressWarnings({"UseSpecificCatch" ,"OverridableMethodCallInConstructor"})
 public class DefaultExpressionBuilder implements ExpressionBuilder {
+    
+    private static final String FORMAT_QUOTE_FOR_STRINGS = "'";
+    private static final String FORMAT_QUOTE_FOR_IDENTIFIERS = "\"";
 
-    public class ConfigBase implements Config {
+    private static final String FORMAT_TRUE = "TRUE";
+    private static final String FORMAT_FALSE = "FALSE";
 
-        protected Map<String, Object> values;
+    private static final String FORMAT_GROUP = "( {0} )";
 
-        public ConfigBase() {
-            this.values = new HashMap<>();
+    private static final String FORMAT_ST_SRID = "ST_SRID({0})";
+    private static final String FORMAT_ST_ASTEXT = "ST_AsText({0})";
+    private static final String FORMAT_ST_ASBINARY = "ST_AsBinary({0})";
+    private static final String FORMAT_ST_ASEWKB = "ST_AsEWKB({0})";
+    private static final String FORMAT_ST_CONTAINS = "ST_Contains(({0}), ({1}))";
+    private static final String FORMAT_ST_CROSSES = "ST_Crosses(({0}), ({1}))";
+    private static final String FORMAT_ST_DISJOINT = "ST_Disjoint(({0}), ({1}))";
+    private static final String FORMAT_ST_EQUALS = "ST_Equals(({0}), ({1}))";
+    private static final String FORMAT_ST_ISCLOSED = "ST_IsClosed({0})";
+    private static final String FORMAT_ST_OVERLAPS = "ST_Overlaps(({0}), ({1}))";
+    private static final String FORMAT_ST_TOUCHES = "ST_Touches(({0}), ({1}))";
+    private static final String FORMAT_ST_WITHIN = "ST_Within(({0}), ({1}))";
+    private static final String FORMAT_ST_ENVELOPE = "ST_Envelope({0})";
+    private static final String FORMAT_ST_INTERSECTS = "ST_Intersects(({0}), ({1}))";
+    private static final String FORMAT_ST_GEOMFROMTEXT = "ST_GeomFromText(({0}), ({1}))";
+    private static final String FORMAT_ST_GEOMFROMWKB = "ST_GeomFromWKB(({0}), ({1}))";
+    private static final String FORMAT_ST_GEOMFROMEWKB = "ST_GeomFromEWKB(({0}), ({1}))";
+    private static final String FORMAT_ST_SIMPLIFY = "ST_Simplify(({0}), ({1}))";
 
-            this.set(Config.has_spatial_functions, true);
-            this.set(Config.support_schemas, true);
-            this.set(Config.constant_true, "(1=1)");
-            this.set(Config.constant_false, "(1=2)");
-            this.set(Config.quote_for_identifiers, "\"");
-            this.set(Config.quote_for_strings, "'");
-            this.set(Config.geometry_type_support, GeometrySupportType.WKB);
-            this.set(Config.group, "( {0} )");
+    private static final String FORMAT_ISNULL = "( ({0}) IS NULL )";
+    private static final String FORMAT_NOTISNULL = "( ({0}) NOT IS NULL )";
+    private static final String FORMAT_OPERATOR_NOT = "( NOT ({0}) )";
 
-            this.set(Config.ST_SRID, "ST_SRID({0})");
-            this.set(Config.ST_AsText, "ST_AsText({0})");
-            this.set(Config.ST_AsBinary, "ST_AsBinary({0})");
-            this.set(Config.ST_AsEWKB, "ST_AsEWKB({0})");
-            this.set(Config.ST_Contains, "ST_Contains(({0}), ({1}))");
-            this.set(Config.ST_Crosses, "ST_Crosses(({0}), ({1}))");
-            this.set(Config.ST_Disjoint, "ST_Disjoint(({0}), ({1}))");
-            this.set(Config.ST_Equals, "ST_Equals(({0}), ({1}))");
-            this.set(Config.ST_IsClosed, "ST_IsClosed({0})");
-            this.set(Config.ST_Overlaps, "ST_Overlaps(({0}), ({1}))");
-            this.set(Config.ST_Touches, "ST_Touches(({0}), ({1}))");
-            this.set(Config.ST_Within, "ST_Within(({0}), ({1}))");
-            this.set(Config.ST_Envelope, "ST_Envelope({0})");
-            this.set(Config.ST_Intersects, "ST_Intersects(({0}), ({1}))");
-            this.set(Config.ST_GeomFromText, "ST_GeomFromText({0}, ({1}))");
-            this.set(Config.ST_GeomFromWKB, "ST_GeomFromWKB(({0}), ({1}))");
-            this.set(Config.ST_GeomFromEWKB, "ST_GeomFromEWKB(({0}), ({1}))");
-            
-            // Por defecto no esta disponible la funcion ST_Simplify
-            // this.set(Config.ST_Simplify, "ST_Simplify(({0}), ({1}))");
-            this.remove_functionality(Config.ST_Simplify);
-            
-            this.set(Config.lcase, "LCASE({0})");
-            this.set(Config.ucase, "UCASE({0})");
-            this.set(Config.iif, "IIF({0},{1},{2})");
-            this.set(Config.ifnull, "IFNULL({0},{1},{2})");
-            
-            this.set(Config.isNull, "( ({0}) IS NULL )");
-            this.set(Config.notIsNull, "( ({0}) NOT IS NULL )");
-            this.set(Config.operator_not, "( NOT ({0}) )");
+    private static final String FORMAT_OPERATOR_AND = "{0} AND {1}";
+    private static final String FORMAT_OPERATOR_OR = "{0} OR {1}";
+    private static final String FORMAT_OPERATOR_EQ = "( ({0}) = ({1}) )";
+    private static final String FORMAT_OPERATOR_NE = "( ({0}) <> ({1}) )";
+    private static final String FORMAT_OPERATOR_GT = "( ({0}) > ({1}) )";
+    private static final String FORMAT_OPERATOR_GE = "( ({0}) >= ({1}) )";
+    private static final String FORMAT_OPERATOR_LT = "( ({0}) < ({1}) )";
+    private static final String FORMAT_OPERATOR_LE = "( ({0}) <= ({1}) )";
+    private static final String FORMAT_OPERATOR_LIKE = "( ({0}) LIKE ({1}) )";
+    private static final String FORMAT_OPERATOR_ILIKE = "( ({0}) ILIKE ({1}) )";
+    private static final String FORMAT_OPERATOR_ADD = "{0} + {1}";
+    private static final String FORMAT_OPERATOR_SUBST = "{0} - {1}";
+    private static final String FORMAT_OPERATOR_MULT = "{0} * {1}";
+    private static final String FORMAT_OPERATOR_DIV = "{0} / {1}";
+    private static final String FORMAT_OPERATOR_CONCAT = "{0} || {1}";
 
-            this.set(Config.operator_AND, "{0} AND {1}");
-            this.set(Config.operator_OR, "{0} OR {1}");
-            this.set(Config.operator_EQ, "( ({0}) = ({1}) )");
-            this.set(Config.operator_NE, "( ({0}) <> ({1}) )");
-            this.set(Config.operator_GT, "( ({0}) > ({1}) )");
-            this.set(Config.operator_GE, "( ({0}) >= ({1}) )");
-            this.set(Config.operator_LT, "( ({0}) < ({1}) )");
-            this.set(Config.operator_LE, "( ({0}) <= ({1}) )");
-            this.set(Config.operator_LIKE, "( ({0}) LIKE ({1}) )");
-            this.set(Config.operator_ILIKE, "( ({0}) ILIKE ({1}) )");
-
-            this.set(Config.operator_add, "{0} + {1}");
-            this.set(Config.operator_subst, "{0} - {1}");
-            this.set(Config.operator_mult, "{0} * {1}");
-            this.set(Config.operator_div, "{0} / {1}");
-            this.set(Config.operator_concat, "{0} || {1}");
-
-        }
-
-        @Override
-        public boolean has_functionality(String functionality) {
-            Object x = this.values.get(functionality);
-            if (x == null) {
-                return false;
-            }
-            if (x instanceof CharSequence && StringUtils.isEmpty((CharSequence) x)) {
-                return false;
-            }
-            return true;
-        }
-
-        @Override
-        public void remove_functionality(String functionality) {
-            this.values.remove(functionality);
-        }
-
-        @Override
-        public boolean has_spatial_functions() {
-            return this.getBoolean(has_spatial_functions);
-        }
-
-        @Override
-        public GeometrySupportType getGeometryTypeSupport() {
-            return (GeometrySupportType) this.get(geometry_type_support);
-        }
-
-        @Override
-        public boolean getBoolean(String name) {
-            return (boolean) this.values.get(name);
-        }
-
-        @Override
-        public String getString(String name) {
-            return (String) this.values.get(name);
-        }
-
-        @Override
-        public Object get(String name) {
-            return this.values.get(name);
-        }
-
-        @Override
-        public void set(String name, Object value) {
-            this.values.put(name, value);
-        }
-    }
-
-    public abstract class AbstractValue implements Value {
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            if (filter == null || filter.accept(this)) {
-                visitor.visit(this);
-            }
-        }
-
-    }
-
-    public class ClassVisitorFilter implements VisitorFilter {
-
-        private final Class classFilter;
-
-        public ClassVisitorFilter(Class classFilter) {
-            this.classFilter = classFilter;
-        }
-
-        @Override
-        public boolean accept(Visitable visitable) {
-            return classFilter.isInstance(visitable);
-        }
-
-    }
-
     public class GroupBase extends AbstractValue implements Group {
 
         protected Value value;
@@ -170,7 +78,7 @@
         }
 
         @Override
-        public Value getValue() {
+        public Value value() {
             return value;
         }
 
@@ -182,8 +90,16 @@
 
         @Override
         public String toString() {
-            return MessageFormat.format(config.getString(Config.group), this.value.toString());
+            return this.toString(EMPTY_FORMATTER);
         }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
+            return MessageFormat.format(FORMAT_GROUP, this.value.toString());
+        }
     }
 
     public class VariableBase extends AbstractValue implements Variable {
@@ -195,18 +111,26 @@
         }
 
         @Override
-        public String getName() {
+        public String name() {
             return this.name;
         }
 
         @Override
         public String toString() {
+            return this.toString(EMPTY_FORMATTER);
+        }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
             return identifier(this.name);
         }
 
         @Override
         public int compareTo(Variable o) {
-            return this.name.compareTo(o.getName());
+            return this.name.compareTo(o.name());
         }
 
         @Override
@@ -214,7 +138,7 @@
             if (!(obj instanceof Variable)) {
                 return false;
             }
-            return this.name.equals(((Variable) obj).getName());
+            return this.name.equals(((Variable) obj).name());
         }
 
         @Override
@@ -232,6 +156,15 @@
         protected ParameterType type;
         protected Value srs;
 
+        /*
+        Para un parametre de tipo Geometria, el srs sera siempre un Constant
+        excepto cuando se le asigne una geometria contante al parametro y esta
+        tenga un SRS asignado. En este caso, tanto la geometria como el SRS
+        se trataran como parametros.
+        
+        Si se quiere que el SRS sea un Parameter, se construira como tal y se 
+        asignara a traves del metodo srs(Value srs).
+        */
         public ParameterBase() {
             this.type = ParameterType.Constant;
             this.name = null;
@@ -284,7 +217,7 @@
 
         @Override
         public Parameter srs(IProjection srs) {
-            this.srs = constant(getSRSId(srs));
+            this.srs = constant(srs_id(srs));
             if( this.type == ParameterType.Variable ) {
                 this.type = ParameterType.Geometry;
             }
@@ -292,7 +225,7 @@
         }
 
         @Override
-        public String getName() {
+        public String name() {
             switch (this.type) {
                 case Variable:
                 case Geometry:
@@ -330,6 +263,12 @@
 
         @Override
         public Parameter value(Object value) {
+            if( value instanceof Geometry ) {
+                if( this.srs == null ) {
+                    IProjection proj = ((Geometry)value).getProjection();
+                    this.srs(parameter().value(proj));
+                }
+            }
             this.value = value;
             return this;
         }
@@ -342,23 +281,23 @@
         }
 
         @Override
-        public Object getValue() {
+        public Object value() {
             try {
                 switch (this.type) {
                     case Constant:
-                        if (this.value instanceof Geometry) {
-                            switch (config.getGeometryTypeSupport()) {
+                        if( this.value instanceof Geometry ) {
+                            Geometry geometry = (Geometry) this.value;
+                            switch (geometry_support_type()) {
                                 case EWKB:
-                                    return bytearray(((Geometry) this.value).convertToEWKB());
-                                case NATIVE:
+                                    return GeometryUtils.toEWKB(geometry);
                                 case WKB:
-                                    return bytearray(((Geometry) this.value).convertToWKB());
+                                    return GeometryUtils.toWKB(geometry);
                                 case WKT:
                                 default:
-                                    return ((Geometry) this.value).convertToWKT();
+                                    return GeometryUtils.toWKT(geometry);
                             }
                         } else if (this.value instanceof IProjection) {
-                            return getSRSId((IProjection) this.value);
+                            return srs_id((IProjection) this.value);
                         }
                         return this.value;
                     case Variable:
@@ -372,46 +311,92 @@
         }
 
         @Override
-        public ParameterType getType() {
+        public ParameterType type() {
             return this.type;
         }
 
         @Override
-        public Value getSRS() {
+        public Value srs() {
             return this.srs;
         }
 
         @Override
         public String toString() {
+            return this.toString(EMPTY_FORMATTER);
+        }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
             switch (this.type) {
                 case Constant:
+                    if( value instanceof Geometry ) {
+                        switch (geometry_support_type()) {
+                            case EWKB:
+                                return MessageFormat.format(
+                                    FORMAT_ST_GEOMFROMEWKB,
+                                    "?",
+                                    getSRS(formatter)
+                                );
+                            case WKB:
+                                return MessageFormat.format(
+                                    FORMAT_ST_GEOMFROMWKB,
+                                    "?",
+                                    getSRS(formatter)
+                                );
+                            case WKT:
+                            default:
+                                return MessageFormat.format(
+                                    FORMAT_ST_GEOMFROMTEXT,
+                                    "?",
+                                    getSRS(formatter)
+                                );
+                        }
+                    }
                 case Variable:
                 default:
                     return "?";
                 case Geometry:
-                    switch (config.getGeometryTypeSupport()) {
+                    switch (geometry_support_type()) {
                         case EWKB:
                             return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromEWKB),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
+                                FORMAT_ST_GEOMFROMEWKB,
+                                "?",
+                                getSRS(formatter)
                             );
                         case WKB:
                             return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromWKB),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
+                                FORMAT_ST_GEOMFROMWKB,
+                                "?",
+                                getSRS(formatter)
                             );
                         case WKT:
                         default:
                             return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromText),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
+                                FORMAT_ST_GEOMFROMTEXT,
+                                "?",
+                                getSRS(formatter)
                             );
                     }
             }
         }
+        
+        private String getSRS(Formatter formatter) {
+            if( this.srs!=null ) {
+                return this.srs.toString(formatter);
+            }
+            if( this.value instanceof Geometry ) {
+                IProjection proj = ((Geometry)this.value).getProjection();
+                Object s = srs_id(proj);
+                if( s == null ) {
+                    throw new IllegalArgumentException("A parameter of type Geometry with an invalid SRS.");
+                }
+                return s.toString();
+            }
+            throw new IllegalArgumentException("The parameter of type Geometry need a SRS.");
+        }
     }
 
     public class ConstantBase extends AbstractValue implements Constant {
@@ -423,23 +408,64 @@
         }
 
         @Override
-        public Object getValue() {
+        public Object value() {
             return this.value;
         }
 
         @Override
         public String toString() {
+            return this.toString(EMPTY_FORMATTER);
+        }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
+            if( this.value==null ) {
+                return "NULL";
+            }
+            if( this.value instanceof byte[] ) {
+                return "DECODE('"+bytearray_hex((byte[])this.value)+"','hex')";
+            }
             if (this.value instanceof String) {
                 return string((String) this.value);
             }
+            if( this.value instanceof Geometry ) {
+                Geometry geometry = (Geometry) this.value;
+                switch (geometry_support_type()) {
+                    case EWKB:
+                        return MessageFormat.format(
+                                FORMAT_ST_GEOMFROMEWKB,
+                                "DECODE('"+bytearray_hex(GeometryUtils.toEWKB(geometry))+"','hex')",
+                                String.valueOf(srs_id(geometry.getProjection()))
+                        );
+                    case WKB:
+                        return MessageFormat.format(
+                                FORMAT_ST_GEOMFROMWKB,
+                                "DECODE('"+bytearray_hex(GeometryUtils.toWKB(geometry))+"','hex')",
+                                String.valueOf(srs_id(geometry.getProjection()))
+                        );
+                    case WKT:
+                    default:
+                        return MessageFormat.format(
+                                FORMAT_ST_GEOMFROMTEXT,
+                                string(GeometryUtils.toWKT(geometry)),
+                                String.valueOf(srs_id(geometry.getProjection()))
+                        );
+                }
+            }
+            if( this.value instanceof IProjection ) {
+                return Objects.toString(srs_id((IProjection)(this.value)));
+            }
             if (this.value instanceof Boolean) {
                 if (((Boolean) this.value)) {
-                    return config.getString(Config.constant_true);
+                    return FORMAT_TRUE;
                 } else {
-                    return config.getString(Config.constant_false);
+                    return FORMAT_FALSE;
                 }
             }
-            return ObjectUtils.toString(this.value, "");
+            return Objects.toString(this.value, "");
         }
     }
 
@@ -466,7 +492,7 @@
         }
 
         @Override
-        public Object getValue() {
+        public Object value() {
             return this.value;
         }
 
@@ -490,57 +516,15 @@
 
         @Override
         public String toString() {
-            return ObjectUtils.toString(this.value, "");
+            return this.toString(EMPTY_FORMATTER);
         }
-    }
-
-    public class GeometryValueBase extends AbstractValue implements GeometryValue {
-
-        protected Geometry geometry;
-        protected IProjection projection;
-
-        public GeometryValueBase(Geometry geometry, IProjection projection) {
-            this.geometry = geometry;
-            this.projection = projection;
-        }
-
+        
         @Override
-        public Geometry getGeometry() {
-            return this.geometry;
-        }
-
-        @Override
-        public IProjection getSRS() {
-            return this.projection;
-        }
-
-        @Override
-        public String toString() {
-            try {
-                switch (config.getGeometryTypeSupport()) {
-                    case EWKB:
-                        return MessageFormat.format(
-                                config.getString(Config.ST_GeomFromEWKB),
-                                bytearray(this.geometry.convertToEWKB()),
-                                String.valueOf(getSRSId(this.projection))
-                        );
-                    case WKB:
-                        return MessageFormat.format(
-                                config.getString(Config.ST_GeomFromWKB),
-                                bytearray(this.geometry.convertToWKB()),
-                                String.valueOf(getSRSId(this.projection))
-                        );
-                    case WKT:
-                    default:
-                        return MessageFormat.format(
-                                config.getString(Config.ST_GeomFromText),
-                                string(this.geometry.convertToWKT()),
-                                String.valueOf(getSRSId(this.projection))
-                        );
-                }
-            } catch (Exception ex) {
-                throw new RuntimeException("Can't convert geometry to string.", ex);
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
             }
+            return Objects.toString(this.value, "");
         }
     }
 
@@ -574,7 +558,7 @@
         }
 
         @Override
-        public String getName() {
+        public String name() {
             return this.name;
         }
 
@@ -588,6 +572,14 @@
 
         @Override
         public String toString() {
+            return this.toString(EMPTY_FORMATTER);
+        }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
             if( this.format==null ) {
                 StringBuilder builder = new StringBuilder();
                 builder.append(name);
@@ -597,10 +589,10 @@
                     for (Value value : this.parameters) {
                         if( first ) {
                             first=false;
-                            builder.append(value.toString());
+                            builder.append(value.toString(formatter));
                         } else {
                             builder.append(", ");
-                            builder.append(value.toString());
+                            builder.append(value.toString(formatter));
                         }
                     }
                 }
@@ -610,7 +602,7 @@
             if (this.parameters != null && !this.parameters.isEmpty()) {
                 List<String> values = new ArrayList<>();
                 for (Value value : this.parameters) {
-                    values.add(value.toString());
+                    values.add(value.toString(formatter));
                 }
                 return MessageFormat.format(format, values.toArray());
             } else {
@@ -619,6 +611,54 @@
         }
     }
 
+    public class MethodBase extends FunctionBase implements Method {
+
+        private final Value instance;
+        
+        public MethodBase(Value instance, String name) {
+            super(name);
+            this.instance = instance;
+        }
+
+        @Override
+        public Value instance() {
+            return this.instance;
+        }
+
+        @Override
+        public void accept(Visitor visitor, VisitorFilter filter) {
+            this.instance.accept(visitor, filter);
+            super.accept(visitor, filter);
+        }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
+            StringBuilder builder = new StringBuilder();
+            builder.append(this.instance.toString(formatter));
+            builder.append("->");
+            builder.append(this.name());
+            builder.append(name);
+            builder.append("(");
+            if (this.parameters != null && !this.parameters.isEmpty()) {
+                boolean first = true;
+                for (Value value : this.parameters) {
+                    if( first ) {
+                        first=false;
+                        builder.append(value.toString(formatter));
+                    } else {
+                        builder.append(", ");
+                        builder.append(value.toString(formatter));
+                    }
+                }
+            }
+            builder.append(")");
+            return builder.toString();
+        }
+    }
+
     public class BinaryOperatorBase extends AbstractValue implements BinaryOperator {
 
         protected String name;
@@ -632,7 +672,7 @@
         }
 
         @Override
-        public String getName() {
+        public String name() {
             return this.name;
         }
 
@@ -644,42 +684,62 @@
         }
 
         @Override
-        public BinaryOperator setLeft(Value operand) {
+        public BinaryOperator left(Value operand) {
             this.left = operand;
             return this;
         }
 
         @Override
-        public BinaryOperator setRight(Value operand) {
+        public BinaryOperator right(Value operand) {
             this.right = operand;
             return this;
         }
 
         @Override
-        public Value getLeft() {
+        public Value left() {
             return this.left;
         }
 
         @Override
-        public Value getRight() {
+        public Value right() {
             return this.right;
         }
 
         @Override
         public String toString() {
-            return MessageFormat.format(
-                    format,
-                    this.left.toString(),
-                    this.right.toString()
-            );
+            return this.toString(EMPTY_FORMATTER);
         }
+        
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if( formatter.canApply(this) ) {
+                return formatter.format(this);
+            }
+            if( this.format==null ) {
+                StringBuilder builder = new StringBuilder();
+                builder.append("(");
+                builder.append(this.left.toString(formatter));
+                builder.append(" ");
+                builder.append(this.name);
+                builder.append(" ");
+                builder.append(this.right.toString(formatter));
+                builder.append(")");
+                return builder.toString();
+            } else {
+                return MessageFormat.format(
+                        format,
+                        this.left.toString(formatter),
+                        this.right.toString(formatter)
+                );
+            }
+        }
     }
 
+    protected GeometrySupportType geometrySupportType;
     protected Value value;
-    protected Config config;
 
     public DefaultExpressionBuilder() {
-        this.config = new ConfigBase();
+        this.geometrySupportType = GeometrySupportType.WKB;
     }
 
     @Override
@@ -688,17 +748,23 @@
     }
 
     @Override
-    public Config getConfig() {
-        return this.config;
+    public GeometrySupportType geometry_support_type() {
+        return this.geometrySupportType;
     }
 
     @Override
-    public Value getValue() {
+    public ExpressionBuilder geometry_support_type(GeometrySupportType geometrySupportType) {
+        this.geometrySupportType = geometrySupportType;
+        return this;
+    }
+
+    @Override
+    public Value value() {
         return this.value;
     }
 
     @Override
-    public ExpressionBuilder setValue(Value value) {
+    public ExpressionBuilder value(Value value) {
         this.value = value;
         return this;
     }
@@ -709,6 +775,21 @@
     }
 
     @Override
+    public String toString(Formatter<Value> formatter) {
+        return this.value.toString(formatter);
+    }
+
+    @Override
+    public Value toValue(String expression) {
+        try {
+            Code code = ExpressionUtils.compile(expression);
+            return code.toValue(this);
+        } catch(Throwable ex) {
+            return custom(expression);
+        }
+    }
+
+    @Override
     public void accept(Visitor visitor, VisitorFilter filter) {
         if( this.value == null) {
             return;
@@ -717,29 +798,29 @@
     }
 
     @Override
-    public boolean has_spatial_functions() {
-        return this.config.getBoolean(Config.has_spatial_functions);
+    public String quote_for_identifiers() {
+        return FORMAT_QUOTE_FOR_IDENTIFIERS;
     }
-
+    
     @Override
-    public GeometrySupportType geometry_support_type() {
-        return (GeometrySupportType) this.config.get(Config.geometry_type_support);
+    public String quote_for_strings() {
+        return FORMAT_QUOTE_FOR_STRINGS;
     }
-
+       
     @Override
     public String string(String s) {
-        String quote = this.config.getString(Config.quote_for_strings);
+        String quote = this.quote_for_strings();
 //        No se porque no esta disponible wrapIfMissing
 //        return StringUtils.wrapIfMissing(s,quote);
         if (s.startsWith(quote)) {
             return s;
         }
-        return quote + s + quote;
+        return quote + StringUtils.replace(s,quote,quote+quote) + quote;
     }
 
     @Override
     public String identifier(String id) {
-        String quote = this.config.getString(Config.quote_for_identifiers);
+        String quote = this.quote_for_identifiers();
 //        No se porque no esta disponible wrapIfMissing
 //        return StringUtils.wrapIfMissing(id,quote);
         if (id.startsWith(quote)) {
@@ -749,11 +830,6 @@
     }
 
     @Override
-    public String bytearray(byte[] data) {
-        return "DECODE('"+bytearray_hex(data)+"','hex')";
-    }
-    
-    @Override
     public String bytearray_hex(byte[] data) {
         StringBuilder builder = new StringBuilder();
         for (byte abyte : data) {
@@ -774,7 +850,7 @@
     }
     
     @Override
-    public Object getSRSId(IProjection projection) {
+    public Object srs_id(IProjection projection) {
         if( projection==null ) {
             return 0;
         }
@@ -782,8 +858,13 @@
     }
 
     @Override
+    public Constant bytearray(byte[] data) {
+        return new ConstantBase(data);
+    }
+    
+    @Override
     public Constant srs(IProjection projection) {
-        return constant(getSRSId(projection));
+        return constant(projection);
     }
 
     @Override
@@ -798,12 +879,13 @@
     
     @Override
     public Parameter parameter(String name) {
-        Parameters parameters = this.getParameters();
-        Parameter parameter = parameters.get(name);
-        if( parameter != null ) {
-            return parameter;
+        List<Parameter> parameters = this.parameters();
+        for (Parameter parameter : parameters) {
+            if( StringUtils.equalsIgnoreCase(name, parameter.name()) ) {
+                return parameter;
+            }
         }
-        parameter = this.parameter();
+        Parameter parameter = this.parameter();
         parameter.name(name);
         return parameter;
     }
@@ -824,29 +906,33 @@
     }
 
     @Override
-    public GeometryValue geometry(Geometry geom, IProjection projection) {
-        return new GeometryValueBase(geom, projection);
+    public Constant geometry(Geometry geom, IProjection projection) {
+        geom.setProjection(projection);
+        return new ConstantBase(geom);
     }
 
     @Override
-    public GeometryValue geometry(Geometry geom) {
+    public Constant geometry(Geometry geom) {
         if( geom.getProjection()==null ) {
             throw new IllegalArgumentException("The geometry does not have an associated projection. Use 'geometry(Geometry, IProjection)'.");
         }
-        return new GeometryValueBase(geom, geom.getProjection());
+        return new ConstantBase(geom);
     }
 
     @Override
-    public GeometryValue envelope(Envelope envelope, IProjection projection) {
-        return new GeometryValueBase(envelope.getGeometry(), projection);
+    public Constant envelope(Envelope envelope, IProjection projection) {
+        Geometry geom = envelope.getGeometry();
+        geom.setProjection(projection);
+        return new ConstantBase(geom);
     }
 
     @Override
-    public GeometryValue envelope(Envelope envelope) {
+    public Constant envelope(Envelope envelope) {
         if( envelope.getProjection()==null ) {
             throw new IllegalArgumentException("The envelope does not have an associated projection. Use 'envelope(Geometry, IProjection)'.");
         }
-        return new GeometryValueBase(envelope.getGeometry(), envelope.getProjection());
+        Geometry geom = envelope.getGeometry();
+        return new ConstantBase(geom);
     }
 
     @Override
@@ -854,6 +940,16 @@
         return new CustomBase(value);
     }
 
+    @Override
+    public Method method(Value instance, String name, Value... values) {
+        MethodBase method = new MethodBase(instance, name);
+        for (Value theValue : values) {
+            method.parameter(theValue);
+        }
+        return method;
+    }
+    
+    @Override
     public Function function(String name, Value... values) {
         FunctionBase func = new FunctionBase(name);
         for (Value theValue : values) {
@@ -870,20 +966,27 @@
         return func;
     }
 
+    @Override
+    public BinaryOperator binaryOperator(String name, Value leftOperand, Value rightOperand) {
+        return binaryOperator(name, null, leftOperand, rightOperand);
+    }
+    
     public BinaryOperator binaryOperator(String name, String format, Value leftOperand, Value rightOperand) {
         BinaryOperator operator = new BinaryOperatorBase(name, format);
-        operator.setLeft(leftOperand);
-        operator.setRight(rightOperand);
+        operator.left(leftOperand);
+        operator.right(rightOperand);
         return operator;
     }
 
     @Override
-    public List<Variable> getVariables() {
+    public List<Variable> variables() {
         final Set<Variable> vars = new HashSet<>();
         this.accept(new Visitor() {
             @Override
             public void visit(Visitable value) {
-                vars.add((Variable) value);
+                if( !vars.contains((Variable)value) ) {
+                    vars.add((Variable)value);
+                }
             }
         }, new ClassVisitorFilter(Variable.class));
         List<Variable> lvars = new ArrayList<>(vars);
@@ -891,75 +994,9 @@
         return lvars;
     }
 
-    private static class ParametersBase extends ArrayList<Parameter> implements Parameters {
-
-        private static final long serialVersionUID = -2188534574151780470L;
-
-        public ParametersBase() {
-            super();
-        }
-
-        public ParametersBase(Collection parameters) {
-            super(parameters);
-        }
-
-        @Override
-        public Parameter get(String name) {
-            if( name == null ) {
-                return null;
-            }
-            for (Parameter param : this) {
-                if( param.is_variable() || param.is_geometry_variable() ) {
-                    if( name.equalsIgnoreCase(param.getName()) ) {
-                        return param;
-                    }
-                }
-            }
-            return null;
-        }
-
-        
-        @Override
-        public String toString() {
-            boolean first = true;
-            StringBuilder builder = new StringBuilder();
-            builder.append("{ ");
-            for (Parameter param : this) {
-                if (!first) {
-                    builder.append(", ");
-                } else {
-                    first = false;
-                }
-                String s;
-                Object value = param.getValue();
-                if (value == null) {
-                    s = "null";
-                } else if (value instanceof String) {
-                    s = "'" + (String) value + "'";
-                } else {
-                    s = value.toString();
-                }
-                switch (param.getType()) {
-                    case Constant:
-                        builder.append(s);
-                        break;
-                    case Geometry:
-                        builder.append("(Geometry)");
-                    case Variable:
-                    default:
-                        builder.append(param.getName());
-                        builder.append(": ");
-                        builder.append(s);
-                }
-            }
-            builder.append(" }");
-            return builder.toString();
-        }
-    }
-
     @Override
-    public Parameters getParameters() {
-        final Parameters params = new ParametersBase();
+    public List<Parameter> parameters() {
+        final List<Parameter>  params = new ArrayList<>();
         this.accept(new Visitor() {
             @Override
             public void visit(Visitable value) {
@@ -968,11 +1005,60 @@
         }, new ClassVisitorFilter(Parameter.class));
         return params;
     }
-
+    
     @Override
-    public Function getAsGeometry(Value value) {
-        return builtin_function("ST_AsBinary", config.getString(Config.ST_AsBinary), value);
+    public List<String> parameters_names() {
+        List<String> params = new ArrayList<>();
+        for (Parameter param : parameters()) {
+            Object theValue = param.value();
+            String s;
+            switch(param.type()) {
+                case Constant:
+                    if( theValue==null ) {
+                        s = "NULL";
+                    } else if( theValue instanceof String ) {
+                        s = "'" + (String)theValue + "'";
+                        
+                    } else if( theValue instanceof byte[] ) {
+                        s = bytearray_0x((byte[]) theValue);
+                        
+                    } else {
+                        s = theValue.toString();
+                    }    
+                    break;
+                case Geometry:
+                    if( param.name()==null ) {
+                        s = bytearray_0x((byte[]) theValue);
+                    } else {
+                        s = "\"" + param.name() + "\"";
+                    }
+                    break;
+                case Variable:
+                default:
+                    s = "\"" + param.name() + "\"";
+            }
+//            if( !params.contains(s) ) { // Ojo que deben ir todos, incluso duplicados.
+                params.add(s);
+//            }
+        }
+        // Collections.sort(params); Ojo, no deben ordenarse.
+        return params;
     }
+    
+    @Override
+    public List<String> variables_names() {
+        List<String> vars = new ArrayList<>();
+        for (Variable var : this.variables()) {
+            vars.add(var.name());
+        }
+        Collections.sort(vars);
+        return vars;
+    }
+    
+    @Override
+    public Function as_geometry(Value value) {
+        return builtin_function(FUNCTION_ST_ASBINARY, FORMAT_ST_ASBINARY, value);
+    }
 
     @Override
     public ExpressionBuilder set(Value value) {
@@ -985,7 +1071,7 @@
         if (this.value == null) {
             return this.set(value);
         }
-        BinaryOperator operator = binaryOperator("AND", config.getString(Config.operator_AND), this.value, value);
+        BinaryOperator operator = binaryOperator(OPERATOR_AND, FORMAT_OPERATOR_AND, this.value, value);
         this.value = operator;
         return this;
     }
@@ -995,438 +1081,474 @@
         if (this.value == null) {
             return this.set(value);
         }
-        BinaryOperator operator = binaryOperator("OR", config.getString(Config.operator_OR), this.value, value);
+        BinaryOperator operator = binaryOperator(OPERATOR_OR, FORMAT_OPERATOR_OR, this.value, value);
         this.value = operator;
         return this;
     }
 
     @Override
     public Function ST_Intersects(Value geom1, Value geom2) {
-        return builtin_function("ST_Intersects", config.getString(Config.ST_Intersects), geom1, geom2);
+        return builtin_function(FUNCTION_ST_INTERSECTS, FORMAT_ST_INTERSECTS, geom1, geom2);
     }
 
     @Override
     public Function ST_SRID(Value geom) {
-        return builtin_function("ST_SRID", config.getString(Config.ST_SRID), geom);
+        return builtin_function(FUNCTION_ST_SRID, FORMAT_ST_SRID, geom);
     }
 
     @Override
     public Function ST_Envelope(Value geom) {
-        return builtin_function("ST_Envelope", config.getString(Config.ST_Envelope), geom);
+        return builtin_function(FUNCTION_ST_ENVELOPE, FORMAT_ST_ENVELOPE, geom);
     }
 
     @Override
     public Function ST_AsText(Value geom) {
-        return builtin_function("ST_AsText", config.getString(Config.ST_AsText), geom);
+        return builtin_function(FUNCTION_ST_ASTEXT, FORMAT_ST_ASTEXT, geom);
     }
 
     @Override
     public Function ST_AsBinary(Value geom) {
-        return builtin_function("ST_AsBinary", config.getString(Config.ST_AsBinary), geom);
+        return builtin_function(FUNCTION_ST_ASBINARY, FORMAT_ST_ASBINARY, geom);
     }
 
     @Override
     public Function ST_AsEWKB(Value geom) {
-        return builtin_function("ST_AsEWKB", config.getString(Config.ST_AsEWKB), geom);
+        return builtin_function(FUNCTION_ST_ASEWKB, FORMAT_ST_ASEWKB, geom);
     }
 
     @Override
     public Function ST_GeomFromText(Value geom, Value crs) {
-        return builtin_function("ST_GeomFromText", config.getString(Config.ST_GeomFromText), geom, crs);
+        return builtin_function(FUNCTION_ST_GEOMFROMTEXT, FORMAT_ST_GEOMFROMTEXT, geom, crs);
     }
 
     @Override
     public Function ST_GeomFromWKB(Value geom, Value crs) {
-        return builtin_function("ST_GeomFromWKB", config.getString(Config.ST_GeomFromWKB), geom, crs);
+        return builtin_function(FUNCTION_ST_GEOMFROMWKB, FORMAT_ST_GEOMFROMWKB, geom, crs);
     }
 
     @Override
     public Function ST_GeomFromEWKB(Value geom, Value crs) {
-        return builtin_function("ST_GeomFromEWKB", config.getString(Config.ST_GeomFromEWKB), geom, crs);
+        return builtin_function(FUNCTION_ST_GEOMFROMEWKB, FORMAT_ST_GEOMFROMEWKB, geom, crs);
     }
 
     @Override
     public Function ST_Simplify(Value geom, Value tolerance) {
-        return builtin_function("ST_Simplify", config.getString(Config.ST_Simplify), tolerance);
+        return builtin_function(FUNCTION_ST_SIMPLIFY, FORMAT_ST_SIMPLIFY, tolerance);
     }
 
     @Override
     public Function ST_Disjoint(Value geom1, Value geom2) {
-        return builtin_function("ST_Disjoint", config.getString(Config.ST_Disjoint), geom1, geom2);
+        return builtin_function(FUNCTION_ST_DISJOINT, FORMAT_ST_DISJOINT, geom1, geom2);
     }
 
     @Override
     public Function ST_Contains(Value geom1, Value geom2) {
-        return builtin_function("ST_Contains", config.getString(Config.ST_Contains), geom1, geom2);
+        return builtin_function(FUNCTION_ST_CONTAINS, FORMAT_ST_CONTAINS, geom1, geom2);
     }
 
     @Override
     public Function ST_Equals(Value geom1, Value geom2) {
-        return builtin_function("ST_Equals", config.getString(Config.ST_Equals), geom1, geom2);
+        return builtin_function(FUNCTION_ST_EQUALS, FORMAT_ST_EQUALS, geom1, geom2);
     }
 
     @Override
     public Function ST_Crosses(Value geom1, Value geom2) {
-        return builtin_function("ST_Crosses", config.getString(Config.ST_Crosses), geom1, geom2);
+        return builtin_function(FUNCTION_ST_CROSSES, FORMAT_ST_CROSSES, geom1, geom2);
     }
 
     @Override
     public Function ST_IsClosed(Value geom) {
-        return builtin_function("ST_IsClosed", config.getString(Config.ST_IsClosed), geom);
+        return builtin_function(FUNCTION_ST_ISCLOSED, FORMAT_ST_ISCLOSED, geom);
     }
 
     @Override
     public Function ST_Overlaps(Value geom1, Value geom2) {
-        return builtin_function("ST_Overlaps", config.getString(Config.ST_Overlaps), geom1, geom2);
+        return builtin_function(FUNCTION_ST_OVERLAPS, FORMAT_ST_OVERLAPS, geom1, geom2);
     }
 
     @Override
     public Function ST_Touches(Value geom1, Value geom2) {
-        return builtin_function("ST_Touches", config.getString(Config.ST_Touches), geom1, geom2);
+        return builtin_function(FUNCTION_ST_TOUCHES, FORMAT_ST_TOUCHES, geom1, geom2);
     }
 
     @Override
     public Function ST_Within(Value geom1, Value geom2) {
-        return builtin_function("ST_Within", config.getString(Config.ST_Within), geom1, geom2);
+        return builtin_function("ST_Within", FORMAT_ST_WITHIN, geom1, geom2);
     }
 
     @Override
-    public Function isNull(Value value) {
-        return builtin_function("IS NULL", config.getString(Config.isNull), value);
+    public Function is_null(Value value) {
+        return builtin_function("IS NULL", FORMAT_ISNULL, value);
     }
 
     @Override
-    public Function notIsNull(Value value) {
-        return builtin_function("NOT IS NULL", config.getString(Config.notIsNull), value);
+    public Function not_is_null(Value value) {
+        return builtin_function("NOT IS NULL", FORMAT_NOTISNULL, value);
     }
 
     @Override
     public Function not(Value value) {
-        return builtin_function("NOT", config.getString(Config.operator_not), value);
+        return builtin_function(OPERATOR_NOT, FORMAT_OPERATOR_NOT, value);
     }
 
     @Override
-    public Function lcase(Value s) {
-        return builtin_function("LCASE", config.getString(Config.lcase), s);
-    }
-
-    @Override
-    public Function ucase(Value s) {
-        return builtin_function("UCASE", config.getString(Config.ucase), s);
-    }
-
-    @Override
     public BinaryOperator and(Value leftOperand, Value rightOperand) {
-        return binaryOperator("AND", config.getString(Config.operator_AND), leftOperand, rightOperand);
+        return binaryOperator(OPERATOR_AND, FORMAT_OPERATOR_AND, leftOperand, rightOperand);
     }
 
     @Override
     public BinaryOperator or(Value leftOperand, Value rightOperand) {
-        return binaryOperator("OR", config.getString(Config.operator_OR), leftOperand, rightOperand);
+        return binaryOperator(OPERATOR_OR, FORMAT_OPERATOR_OR, leftOperand, rightOperand);
     }
 
     @Override
     public BinaryOperator eq(Value leftOperand, Value rightOperand) {
-        return binaryOperator("=", config.getString(Config.operator_EQ), leftOperand, rightOperand);
+        return binaryOperator("=", FORMAT_OPERATOR_EQ, leftOperand, rightOperand);
     }
 
     @Override
     public BinaryOperator ne(Value leftOperand, Value rightOperand) {
-        return binaryOperator("<>", config.getString(Config.operator_NE), leftOperand, rightOperand);
+        return binaryOperator("<>", FORMAT_OPERATOR_NE, leftOperand, rightOperand);
     }
 
     @Override
     public BinaryOperator gt(Value op1, Value op2) {
-        return binaryOperator(">", config.getString(Config.operator_GT), op1, op2);
+        return binaryOperator(">", FORMAT_OPERATOR_GT, op1, op2);
     }
 
     @Override
     public BinaryOperator ge(Value op1, Value op2) {
-        return binaryOperator(">=", config.getString(Config.operator_GE), op1, op2);
+        return binaryOperator(">=", FORMAT_OPERATOR_GE, op1, op2);
     }
 
     @Override
     public BinaryOperator lt(Value op1, Value op2) {
-        return binaryOperator("<", config.getString(Config.operator_LT), op1, op2);
+        return binaryOperator("<", FORMAT_OPERATOR_LT, op1, op2);
     }
 
     @Override
     public BinaryOperator le(Value op1, Value op2) {
-        return binaryOperator("<=", config.getString(Config.operator_LE), op1, op2);
+        return binaryOperator("<=", FORMAT_OPERATOR_LE, op1, op2);
     }
 
     @Override
     public BinaryOperator like(Value op1, Value op2) {
-        return binaryOperator("LIKE", config.getString(Config.operator_LIKE), op1, op2);
+        return binaryOperator(OPERATOR_LIKE, FORMAT_OPERATOR_LIKE, op1, op2);
     }
 
     @Override
     public BinaryOperator ilike(Value op1, Value op2) {
-        return binaryOperator("ILIKE", config.getString(Config.operator_ILIKE), op1, op2);
+        return binaryOperator(OPERATOR_ILIKE, FORMAT_OPERATOR_ILIKE, op1, op2);
     }
 
     @Override
     public BinaryOperator add(Value op1, Value op2) {
-        return binaryOperator("ADD", config.getString(Config.operator_add), op1, op2);
+        return binaryOperator(OPERATOR_ADD, FORMAT_OPERATOR_ADD, op1, op2);
     }
 
     @Override
     public BinaryOperator subst(Value op1, Value op2) {
-        return binaryOperator("SUBST", config.getString(Config.operator_subst), op1, op2);
+        return binaryOperator(OPERATOR_SUBST, FORMAT_OPERATOR_SUBST, op1, op2);
     }
 
     @Override
     public BinaryOperator mult(Value op1, Value op2) {
-        return binaryOperator("MULT", config.getString(Config.operator_mult), op1, op2);
+        return binaryOperator(OPERATOR_MULT, FORMAT_OPERATOR_MULT, op1, op2);
     }
 
     @Override
     public BinaryOperator div(Value op1, Value op2) {
-        return binaryOperator("DIV", config.getString(Config.operator_div), op1, op2);
+        return binaryOperator(OPERATOR_DIV, FORMAT_OPERATOR_DIV, op1, op2);
     }
 
     @Override
     public BinaryOperator concat(Value op1, Value op2) {
-        return binaryOperator("CONCAT", config.getString(Config.operator_concat), op1, op2);
+        return binaryOperator(OPERATOR_CONCAT, FORMAT_OPERATOR_CONCAT, op1, op2);
     }
     
     @Override
     public Function iif(Value condition, Value iftrue, Value iffalse) {
-        return builtin_function("IIF", config.getString(Config.iif), condition, iftrue, iffalse);
+        return function(FUNCTION_IIF, condition, iftrue, iffalse);
     }
 
     @Override
     public Function ifnull(Value value, Value iftrue, Value iffalse) {
-        return builtin_function("IFNULL", config.getString(Config.ifnull), value, iftrue, iffalse);
+        return function(FUNCTION_IFNULL, value, iftrue, iffalse);
     }
     
     @Override
     public Function left(Value str, Value size) {
-       return function("left", str, size);
-       // return builtin_function("left", "left({1})",str,size);
+       return function(FUNCTION_LEFT, str, size);
     }
     
     @Override
     public Function right(Value str, Value len) {
-       return function("right", str, len);
+       return function(FUNCTION_RIGHT, str, len);
     }
     
     @Override
     public Function locate(Value search, Value str, Value start) {
-       return function("locate", search, str, start);
+       return function(FUNCTION_LOCATE, search, str, start);
     }
     
     @Override
     public Function position(Value search, Value str) {
-       return function("position", search, str);
+       return function(FUNCTION_POSITION, search, str);
     }
     
     @Override
     public Function lpad(Value str, Value len, Value padstr) {
-       return function("lpad", str, len, padstr);
+       return function(FUNCTION_LPAD, str, len, padstr);
     }
     
     @Override
     public Function rpad(Value str, Value len, Value padstr) {
-       return function("rpad", str, len, padstr);
+       return function(FUNCTION_RPAD, str, len, padstr);
     }
     
     @Override
     public Function ltrim(Value str) {
-       return function("ltrim", str);
+       return function(FUNCTION_LTRIM, str);
     }
     
     @Override
     public Function rtrim(Value str) {
-       return function("rtrim", str);
+       return function(FUNCTION_RTRIM, str);
     }
     
     @Override
     public Function trim(Value str) {
-       return function("trim", str);
+       return function(FUNCTION_TRIM, str);
     }
     
     @Override
     public Function repeat(Value str, Value size) {
-       return function("repeat", str, size);
+       return function(FUNCTION_REPEAT, str, size);
     }
     
     @Override
     public Function replace(Value str, Value search, Value replstr) {
-       return function("replace", str, search, replstr);
+       return function(FUNCTION_REPLACE, str, search, replstr);
     }
     
     @Override
     public Function ascii(Value str) {
-       return function("ascii", str);
+       return function(FUNCTION_ASCII, str);
     }
     
     @Override
     public Function lenght(Value str) {
-       return function("lenght", str);
+       return function(FUNCTION_LENGHT, str);
     }
 
     @Override
     public Function instr(Value str, Value search, Value start) {
-       return function("instr", str, search, start);
+       return function(FUNCTION_INSTR, str, search, start);
     }
     
     @Override
     public Function lower(Value str) {
-       return function("lower", str);
+       return function(FUNCTION_LOWER, str);
     }
     
     @Override
     public Function upper(Value str) {
-       return function("upper", str);
+       return function(FUNCTION_UPPER, str);
     }
     
     @Override
     public Function space(Value size) {
-       return function("space", size);
+       return function(FUNCTION_SPACE, size);
     }
     
     @Override
     public Function substring(Value str, Value start, Value len) {
-       return function("substring", str, start, len);
+       return function(FUNCTION_SUBSTRING, str, start, len);
     }
     
     @Override
     public Function acos(Value num) {
-       return function("acos", num);
+       return function(FUNCTION_ACOS, num);
     } 
     
     @Override
     public Function asin(Value num) {
-       return function("asin", num);
+       return function(FUNCTION_ASIN, num);
     }
     
     @Override
     public Function atan(Value num) {
-       return function("atan", num);
+       return function(FUNCTION_ATAN, num);
     }
     
     @Override
     public Function cos(Value num) {
-       return function("cos", num);
+       return function(FUNCTION_COS, num);
     }
     
     @Override
     public Function cosh(Value num) {
-       return function("cosh", num);
+       return function(FUNCTION_COSH, num);
     }
     
     @Override
     public Function cot(Value num) {
-       return function("cot", num);
+       return function(FUNCTION_COT, num);
     }  
     
     @Override
     public Function bitand(Value num1, Value num2) {
-       return function("bitand", num1, num2);
+       return function(FUNCTION_BITAND, num1, num2);
     } 
     
     @Override
     public Function bitor(Value num1, Value num2) {
-       return function("bitor", num1, num2);
+       return function(FUNCTION_BITOR, num1, num2);
     }
     
     @Override
     public Function bitxor(Value num1, Value num2) {
-       return function("bitxor", num1, num2);
+       return function(FUNCTION_BITXOR, num1, num2);
     }
     
     @Override
     public Function ceil(Value num) {
-       return function("ceil", num);
+       return function(FUNCTION_CEIL, num);
     }
     
     @Override
     public Function degrees(Value num) {
-       return function("degrees", num);
+       return function(FUNCTION_DEGREES, num);
     }  
     
     @Override
     public Function exp(Value num) {
-       return function("exp", num);
+       return function(FUNCTION_EXP, num);
     }  
     
     @Override
     public Function floor(Value num) {
-       return function("floor", num);
+       return function(FUNCTION_FLOOR, num);
     }  
     
     @Override
     public Function log(Value num) {
-       return function("log", num);
+       return function(FUNCTION_LOG, num);
     }  
     
     @Override
     public Function log10(Value num) {
-       return function("log10", num);
+       return function(FUNCTION_LOG10, num);
     }  
     
     @Override
     public Function pi(Value num) {
-       return function("pi", num);
+       return function(FUNCTION_PI, num);
     }
     
     @Override
     public Function power(Value num) {
-       return function("power", num);
+       return function(FUNCTION_POWER, num);
     }
     
     @Override
     public Function radians(Value num) {
-       return function("radians", num);
+       return function(FUNCTION_RADIANS, num);
     }
     
     @Override
     public Function rand(Value num) {
-       return function("rand", num);
+       return function(FUNCTION_RAND, num);
     }
     
     @Override
     public Function round(Value num) {
-       return function("round", num);
+       return function(FUNCTION_ROUND, num);
     }
     
     @Override
     public Function sqrt(Value num) {
-       return function("sqrt", num);
+       return function(FUNCTION_SQRT, num);
     }
     
     @Override
     public Function sign(Value num) {
-       return function("sign", num);
+       return function(FUNCTION_SIGN, num);
     }
     
     @Override
     public Function sin(Value num) {
-       return function("sin", num);
+       return function(FUNCTION_SIN, num);
     }
     
     @Override
     public Function sinh(Value num) {
-       return function("sinh", num);
+       return function(FUNCTION_SINH, num);
     }
     
     @Override
     public Function tan(Value num) {
-       return function("tan", num);
+       return function(FUNCTION_TAN, num);
     }
     @Override
     public Function tanh(Value num) {
-       return function("cosh", num);
+       return function(FUNCTION_TANH, num);
     }  
     
     @Override
     public Function zero() {
-       return function("zero");
+       return function(FUNCTION_ZERO);
     }
     
     @Override
     public Function chr(Value num) {
-       return function("chr", num);
+       return function(FUNCTION_CHR, num);
+    }    
+
+    @Override
+    public Function ST_ExtentAggregate(Value geom) {
+       return function(FUNCTION_ST_EXTENTAGGREGATE, geom);
     }
+
+    @Override
+    public Function ST_UnionAggregate(Value geom) {
+       return function(FUNCTION_ST_UNIONAGGREGATE, geom);
+    }
+
+    @Override
+    public Function cast(Value object, Value typeName) {
+       return function(FUNCTION_CAST, object, typeName);
+    }    
+
+    @Override
+    public Function decode(Value value, Value format) {
+       return function(FUNCTION_DECODE, value, format);
+    }    
+
+    @Override
+    public Function toDouble(Value num) {
+       return function(FUNCTION_TODOUBLE, num);
+    }    
+
+    @Override
+    public Function toFloat(Value num) {
+       return function(FUNCTION_TOFLOAT, num);
+    }    
+
+    @Override
+    public Function toLong(Value num) {
+       return function(FUNCTION_TOLONG, num);
+    }    
+
+    @Override
+    public Function toInteger(Value num) {
+       return function(FUNCTION_TOINTEGER, num);
+    }    
+
+    @Override
+    public Function toStr(Value object) {
+       return function(FUNCTION_TOSTR, object);
+    }    
+
+
 }
