Index: SQLBuilderBase.java
===================================================================
--- SQLBuilderBase.java	(revision 44197)
+++ SQLBuilderBase.java	(revision 44198)
@@ -2,7 +2,6 @@
 
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -10,15 +9,22 @@
 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.apache.commons.lang3.tuple.ImmutablePair;
 import org.apache.commons.lang3.tuple.Pair;
 import org.cresques.cts.IProjection;
 import org.gvsig.expressionevaluator.ExpressionBuilder;
-import static org.gvsig.expressionevaluator.ExpressionBuilder.Config.geometry_type_support;
-import static org.gvsig.expressionevaluator.ExpressionBuilder.Config.has_spatial_functions;
+import org.gvsig.expressionevaluator.ExpressionBuilder.AbstractValue;
+import org.gvsig.expressionevaluator.ExpressionBuilder.ClassVisitorFilter;
+import org.gvsig.expressionevaluator.ExpressionBuilder.GeometrySupportType;
+import org.gvsig.expressionevaluator.ExpressionBuilder.Parameter;
+import org.gvsig.expressionevaluator.ExpressionBuilder.Value;
+import org.gvsig.expressionevaluator.ExpressionBuilder.Variable;
+import org.gvsig.expressionevaluator.ExpressionBuilder.Visitable;
+import org.gvsig.expressionevaluator.ExpressionBuilder.Visitor;
+import org.gvsig.expressionevaluator.ExpressionBuilder.VisitorFilter;
 import org.gvsig.expressionevaluator.ExpressionEvaluatorLocator;
+import org.gvsig.expressionevaluator.Formatter;
 import org.gvsig.fmap.dal.DataStoreParameters;
 import org.gvsig.fmap.dal.DataTypes;
 import org.gvsig.fmap.dal.SQLBuilder;
@@ -32,7 +38,6 @@
 import org.gvsig.fmap.dal.SQLBuilder.InsertColumnBuilder;
 import org.gvsig.fmap.dal.SQLBuilder.OrderByBuilder;
 import org.gvsig.fmap.dal.SQLBuilder.Privilege;
-import org.gvsig.fmap.dal.SQLBuilder.SQLConfig;
 import org.gvsig.fmap.dal.SQLBuilder.SelectBuilder;
 import org.gvsig.fmap.dal.SQLBuilder.SelectColumnBuilder;
 import org.gvsig.fmap.dal.SQLBuilder.TableNameBuilder;
@@ -40,16 +45,15 @@
 import org.gvsig.fmap.dal.SQLBuilder.UpdateColumnBuilder;
 import org.gvsig.fmap.dal.SQLBuilder.UpdateTableStatisticsBuilder;
 import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
-import org.gvsig.fmap.dal.feature.FeatureStore;
 import org.gvsig.fmap.geom.Geometry;
-import org.gvsig.fmap.geom.primitive.Envelope;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+@SuppressWarnings("UseSpecificCatch")
 public class SQLBuilderBase implements SQLBuilder {
-    
-    protected static final Logger logger = LoggerFactory.getLogger(SQLBuilderBase.class);
-    
+
+    protected static final Logger LOGGER = LoggerFactory.getLogger(SQLBuilderBase.class);
+
     protected SelectBuilder select;
     protected UpdateBuilder update;
     protected InsertBuilder insert;
@@ -60,116 +64,15 @@
     protected DropTableBuilder drop_table;
     protected UpdateTableStatisticsBuilder update_table_statistics;
     protected CreateIndexBuilder create_index;
-    protected List<Parameter> parameters;
 
-    public class ConfigBase implements Config {
+    protected abstract class AbstractStatementPart extends AbstractValue {
 
-        protected Map<String, Object> values;
-
-        public ConfigBase() {
-            this.values = new HashMap<>();
-
-        }
-
-        @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 {
+    protected abstract class AbstractStatement extends AbstractStatementPart {
 
-        @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;
-
-        public GroupBase(Value value) {
-            this.value = value;
-        }
-
-        @Override
-        public Value getValue() {
-            return value;
-        }
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            super.accept(visitor, filter);
-            this.value.accept(visitor, filter);
-        }
-
-        @Override
-        public String toString() {
-            return MessageFormat.format(config.getString(Config.group), this.value.toString());
-        }
-    }
-    
     protected class ColumnDescriptorBase implements ColumnDescriptor {
 
         private String name;
@@ -215,7 +118,7 @@
             this.geom_srsdbcode = null;
             this._isIndexed = isIndexed;
         }
-        
+
         public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
             this.name = name;
             this.type = DataTypes.GEOMETRY;
@@ -227,10 +130,10 @@
             this.defaultValue = null;
             this.geom_type = geom_type;
             this.geom_subtype = geom_subtype;
-            this.geom_srsdbcode = getSRSId(proj);
+            this.geom_srsdbcode = srs_id(proj);
             this._isIndexed = isIndexed;
         }
-        
+
         public ColumnDescriptorBase(String name, int geom_type, int geom_subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
             this.name = name;
             this.type = DataTypes.GEOMETRY;
@@ -245,12 +148,29 @@
             this.geom_srsdbcode = srsdbcode;
             this._isIndexed = isIndexed;
         }
-        
+
+        private ColumnDescriptorBase(FeatureAttributeDescriptor fad) {
+            this(fad.getName(), fad.getType(), fad.getDefaultValue());
+            this.type_p = fad.getPrecision();
+            this.type_s = fad.getSize();
+            this.isPk = fad.isPrimaryKey();
+            this._allowNulls = fad.allowNull();
+            this._isAutomatic = fad.isAutomatic();
+            this._isIndexed = fad.isIndexed();
+
+            if (fad.getType() == org.gvsig.fmap.geom.DataTypes.GEOMETRY) {
+                this.geom_type = fad.getGeomType().getType();
+                this.geom_subtype = fad.getGeomType().getSubType();
+                this.geom_srsdbcode = fad.getSRS();
+            }
+        }
+    
+
         @Override
         public String getName() {
             return this.name;
         }
-        
+
         @Override
         public void setName(String name) {
             this.name = name;
@@ -359,7 +279,7 @@
         @Override
         public void setGeometrySRSId(Object geom_srsid) {
             this.geom_srsdbcode = geom_srsid;
-        }        
+        }
 
         @Override
         public boolean isGeometry() {
@@ -375,513 +295,71 @@
             return this.parameters;
         }
     }
+//
+//    public class ColumnBase extends AbstractValue implements Column {
+//
+//        protected ColumnDescriptor descriptor;
+//        protected String name;
+//
+//        public ColumnBase(ColumnDescriptor descriptor) {
+//            this.name = descriptor.getName();
+//            this.descriptor = descriptor;
+//        }
+//
+//        public ColumnBase(String name) {
+//            this.name = name;
+//            this.descriptor = null;
+//        }
+//
+//        @Override
+//        public ColumnDescriptor getDescriptor() {
+//            return descriptor;
+//        }
+//
+//        @Override
+//        public String name() {
+//            return this.name;
+//        }
+//
+//        @Override
+//        public String toString() {
+//            return this.toString(formatter());
+//        }
+//
+//        @Override
+//        public String toString(Formatter<Value> formatter) {
+//            if (formatter.canApply(this)) {
+//                return formatter.format(this);
+//            }
+//            return as_identifier(this.name);
+//        }
+//
+//        @Override
+//        public int compareTo(ExpressionBuilder.Variable o) {
+//            return this.name.compareTo(o.name());
+//        }
+//
+//        @Override
+//        public boolean equals(Object obj) {
+//            if (!(obj instanceof ExpressionBuilder.Variable)) {
+//                return false;
+//            }
+//            return this.name.equals(((ExpressionBuilder.Variable) obj).name());
+//        }
+//
+//        @Override
+//        public int hashCode() {
+//            int hash = 7;
+//            hash = 37 * hash + Objects.hashCode(this.name);
+//            return hash;
+//        }
+//
+//    }
 
-    public class VariableBase extends AbstractValue implements Column {
+    public class TableNameBuilderBase
+            extends AbstractStatementPart
+            implements TableNameBuilder {
 
-        protected ColumnDescriptor descriptor;
-        protected String name;
-
-
-        public VariableBase(ColumnDescriptor descriptor) {
-            this.name = descriptor.getName();
-            this.descriptor = descriptor;
-        }
-
-        public VariableBase(String name) {
-            this.name = name;
-            this.descriptor = null;
-        }
-
-        @Override
-        public ColumnDescriptor getDescriptor() {
-            return descriptor;
-        }
-
-        @Override
-        public String getName() {
-            return this.name;
-        }
-
-        @Override
-        public String toString() {
-            return identifier(this.name);
-        }
-
-        @Override
-        public int compareTo(ExpressionBuilder.Variable o) {
-            return this.name.compareTo(o.getName());
-        }
-
-        @Override
-        public boolean equals(Object obj) {
-            if (!(obj instanceof ExpressionBuilder.Variable)) {
-                return false;
-            }
-            return this.name.equals(((ExpressionBuilder.Variable) obj).getName());
-        }
-
-        @Override
-        public int hashCode() {
-            int hash = 7;
-            hash = 37 * hash + Objects.hashCode(this.name);
-            return hash;
-        }
-
-    }
-
-    
-    public class ParameterBase extends AbstractValue implements Parameter {
-
-        protected String name;
-        protected Object value;
-        protected ParameterType type;
-        protected Value srs;
-
-        public ParameterBase() {
-            this.type = ParameterType.Constant;
-            this.name = null;
-            this.value = null;
-        }
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            super.accept(visitor, filter);
-            if (this.srs != null) {
-                this.srs.accept(visitor, filter);
-            }
-        }
-
-        @Override
-        public Parameter as_geometry_variable() {
-            this.type = ParameterType.Geometry;
-            if (this.value == null && this.name != null) {
-                this.value = this.name;
-            }
-            return this;
-        }
-
-        @Override
-        public Parameter as_constant() {
-            this.type = ParameterType.Constant;
-            if (this.value == null && this.name != null) {
-                this.value = this.name;
-            }
-            return this;
-        }
-
-        @Override
-        public Parameter as_variable() {
-            this.type = ParameterType.Variable;
-            if (this.value != null && this.name == null) {
-                this.name = (String) this.value;
-            }
-            return this;
-        }
-
-        @Override
-        public Parameter srs(Value srs) {
-            this.srs = srs;
-            if( this.type == ParameterType.Variable ) {
-                this.type = ParameterType.Geometry;
-            }
-            return this;
-        }
-
-        @Override
-        public Parameter srs(IProjection srs) {
-            this.srs = constant(getSRSId(srs));
-            if( this.type == ParameterType.Variable ) {
-                this.type = ParameterType.Geometry;
-            }
-            return this;
-        }
-
-        @Override
-        public String getName() {
-            switch (this.type) {
-                case Variable:
-                case Geometry:
-                    return this.name;
-                case Constant:
-                    if (this.value == null) {
-                        return null;
-                    }
-                    return this.value.toString();
-                default:
-                    if (this.name != null) {
-                        return this.name;
-                    }
-                    if (this.value != null) {
-                        return this.value.toString();
-                    }
-                    return null;
-            }
-        }
-
-        @Override
-        public boolean is_constant() {
-            return this.type == ParameterType.Constant;
-        }
-
-        @Override
-        public boolean is_geometry_variable() {
-            return this.type == ParameterType.Geometry;
-        }
-
-        @Override
-        public boolean is_variable() {
-            return this.type == ParameterType.Variable;
-        }
-
-        @Override
-        public Parameter value(Object value) {
-            this.value = value;
-            return this;
-        }
-
-        @Override
-        public Parameter name(String name) {
-            this.type = ParameterType.Variable;
-            this.name = name;
-            return this;
-        }
-
-        @Override
-        public Object getValue() {
-            try {
-                switch (this.type) {
-                    case Constant:
-                        if (this.value instanceof Geometry) {
-                            switch (config.getGeometryTypeSupport()) {
-                                case EWKB:
-                                    return bytearray(((Geometry) this.value).convertToEWKB());
-                                case NATIVE:
-                                case WKB:
-                                    return bytearray(((Geometry) this.value).convertToWKB());
-                                case WKT:
-                                default:
-                                    return ((Geometry) this.value).convertToWKT();
-                            }
-                        } else if (this.value instanceof IProjection) {
-                            return getSRSId((IProjection) this.value);
-                        }
-                        return this.value;
-                    case Variable:
-                    case Geometry:
-                    default:
-                        return this.value;
-                }
-            } catch (Exception ex) {
-                throw new RuntimeException("Can't get value from parameter.", ex);
-            }
-        }
-
-        @Override
-        public ParameterType getType() {
-            return this.type;
-        }
-
-        @Override
-        public Value getSRS() {
-            return this.srs;
-        }
-
-        @Override
-        public String toString() {
-            switch (this.type) {
-                case Constant:
-                case Variable:
-                default:
-                    return "?";
-                case Geometry:
-                    switch (config.getGeometryTypeSupport()) {
-                        case EWKB:
-                            return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromEWKB),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
-                            );
-                        case WKB:
-                            return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromWKB),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
-                            );
-                        case WKT:
-                        default:
-                            return MessageFormat.format(
-                                    config.getString(Config.ST_GeomFromText),
-                                    "?",
-                                    String.valueOf(this.srs.toString())
-                            );
-                    }
-            }
-        }
-    }
-
-    public class ConstantBase extends AbstractValue implements Constant {
-
-        protected Object value;
-
-        public ConstantBase(Object value) {
-            this.value = value;
-        }
-
-        @Override
-        public Object getValue() {
-            return this.value;
-        }
-
-        @Override
-        public String toString() {
-            if (this.value instanceof String) {
-                return string((String) this.value);
-            }
-            if (this.value instanceof Boolean) {
-                if (((Boolean) this.value)) {
-                    return config.getString(Config.constant_true);
-                } else {
-                    return config.getString(Config.constant_false);
-                }
-            }
-            return ObjectUtils.toString(this.value, "");
-        }
-    }
-
-    public class CustomBase extends AbstractValue implements Custom {
-
-        protected Object value;
-
-        // Esto es para permitir declarar parametros y columnas en una seccion
-        // custom.
-        protected List<Value> values;
-
-        public CustomBase(Object value) {
-            this.value = value;
-        }
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            super.accept(visitor, filter);
-            if (this.values != null) {
-                for (Value value : values) {
-                    value.accept(visitor, filter);
-                }
-            }
-        }
-
-        @Override
-        public Object getValue() {
-            return this.value;
-        }
-
-        @Override
-        public Custom add(Variable variable) {
-            if (this.values == null) {
-                this.values = new ArrayList<>();
-            }
-            this.values.add(variable);
-            return this;
-        }
-
-        @Override
-        public Custom add(Parameter parameter) {
-            if (this.values == null) {
-                this.values = new ArrayList<>();
-            }
-            this.values.add(parameter);
-            return this;
-        }
-
-        @Override
-        public String toString() {
-            return ObjectUtils.toString(this.value, "");
-        }
-    }
-
-    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 class FunctionBase extends AbstractValue implements Function {
-
-        protected String name;
-        protected String format;
-        protected List<Value> parameters;
-
-        public FunctionBase(String name, String format) {
-            this.name = name;
-            this.format = format;
-        }
-
-        public FunctionBase(String name) {
-            this(name,null);
-        }
-        
-        @Override
-        public List<Value> parameters() {
-            if (this.parameters == null) {
-                this.parameters = new ArrayList<>();
-            }
-            return this.parameters;
-        }
-
-        @Override
-        public Function parameter(Value parameter) {
-            this.parameters().add(parameter);
-            return this;
-        }
-
-        @Override
-        public String getName() {
-            return this.name;
-        }
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            super.accept(visitor, filter);
-            for (Value value : this.parameters) {
-                value.accept(visitor, filter);
-            }
-        }
-
-        @Override
-        public String toString() {
-            if( this.format==null ) {
-                StringBuilder builder = new StringBuilder();
-                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());
-                        } else {
-                            builder.append(", ");
-                            builder.append(value.toString());
-                        }
-                    }
-                }
-                builder.append(")");
-                return builder.toString();
-            }
-            if (this.parameters != null && !this.parameters.isEmpty()) {
-                List<String> values = new ArrayList<>();
-                for (Value value : this.parameters) {
-                    values.add(value.toString());
-                }
-                return MessageFormat.format(format, values.toArray());
-            } else {
-                return this.format;
-            }
-        }
-    }
-
-    public class BinaryOperatorBase extends AbstractValue implements BinaryOperator {
-
-        protected String name;
-        protected String format;
-        protected Value left;
-        protected Value right;
-
-        public BinaryOperatorBase(String name, String format) {
-            this.name = name;
-            this.format = format;
-        }
-
-        @Override
-        public String getName() {
-            return this.name;
-        }
-
-        @Override
-        public void accept(Visitor visitor, VisitorFilter filter) {
-            super.accept(visitor, filter);
-            this.left.accept(visitor, filter);
-            this.right.accept(visitor, filter);
-        }
-
-        @Override
-        public BinaryOperator setLeft(Value operand) {
-            this.left = operand;
-            return this;
-        }
-
-        @Override
-        public BinaryOperator setRight(Value operand) {
-            this.right = operand;
-            return this;
-        }
-
-        @Override
-        public Value getLeft() {
-            return this.left;
-        }
-
-        @Override
-        public Value getRight() {
-            return this.right;
-        }
-
-        @Override
-        public String toString() {
-            return MessageFormat.format(
-                    format,
-                    this.left.toString(),
-                    this.right.toString()
-            );
-        }
-    }
-    
-    public class TableNameBuilderBase implements TableNameBuilder {
-
         public String tableName;
         public String schemaName;
         private String databaseName;
@@ -891,7 +369,7 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
         }
@@ -904,7 +382,7 @@
 
         @Override
         public TableNameBuilder schema(String name) {
-            if( supportSchemas() ) {
+            if (support_schemas()) {
                 this.schemaName = name;
             }
             return this;
@@ -930,10 +408,10 @@
         public String getName() {
             return this.tableName;
         }
-        
+
         @Override
         public boolean has_schema() {
-            if( !supportSchemas() ) {
+            if (!support_schemas()) {
                 return false;
             }
             return !StringUtils.isEmpty(this.schemaName);
@@ -943,38 +421,48 @@
         public boolean has_database() {
             return !StringUtils.isEmpty(this.databaseName);
         }
-        
+
         @Override
         public String toString() {
-            if( this.has_database()) {
-                if( this.has_schema()) {
-                    return identifier(this.databaseName) + "." + 
-                           identifier(this.schemaName) + "." + 
-                           identifier(this.tableName);
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
+            if (this.has_database()) {
+                if (this.has_schema()) {
+                    return as_identifier(this.databaseName) + "."
+                            + as_identifier(this.schemaName) + "."
+                            + as_identifier(this.tableName);
                 }
             } else {
-                if( this.has_schema()) {
-                    return identifier(this.schemaName) + "." + 
-                           identifier(this.tableName);
-                }                
+                if (this.has_schema()) {
+                    return as_identifier(this.schemaName) + "."
+                            + as_identifier(this.tableName);
+                }
             }
-            return identifier(this.tableName);
+            return as_identifier(this.tableName);
         }
 
     }
 
-    public class CountBuilderBase extends AbstractValue implements CountBuilder {
+    public class CountBuilderBase
+            extends AbstractStatementPart
+            implements CountBuilder {
 
         protected Value value;
         protected boolean distinct;
-        protected boolean all ;
-        
+        protected boolean all;
+
         public CountBuilderBase() {
             this.value = null;
             this.distinct = false;
             this.all = false;
         }
-        
+
         @Override
         public CountBuilder all() {
             this.all = true;
@@ -995,36 +483,42 @@
 
         @Override
         public String toString() {
-            if( this.all ) {
-                return MessageFormat.format(
-                    config.getString(SQLConfig.count),
-                    "*"
-                );
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
             }
-            if( this.distinct ) {
+            if (this.all) {
+                return "COUNT(*)";
+            }
+            if (this.distinct) {
                 return MessageFormat.format(
-                    config.getString(SQLConfig.count_distinct),
-                    value.toString()
+                        "COUNT(DISTINCT {0})",
+                        value.toString(formatter)
                 );
             }
             return MessageFormat.format(
-                config.getString(SQLConfig.count),
-                value.toString()
+                    "COUNT({0})",
+                    value.toString(formatter)
             );
         }
-        
-        
+
     }
-    
-    public class FromBuilderBase implements FromBuilder {
 
-        protected TableNameBuilder tableName= null;
+    public class FromBuilderBase
+            extends AbstractStatementPart
+            implements FromBuilder {
+
+        protected TableNameBuilder tableName = null;
         private String subquery = null;
         private String passthrough = null;
 
         @Override
         public TableNameBuilder table() {
-            if( tableName == null ) {
+            if (tableName == null) {
                 this.tableName = createTableNameBuilder();
             }
             return this.tableName;
@@ -1032,10 +526,10 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.tableName != null ) {
+            if (this.tableName != null) {
                 this.tableName.accept(visitor, filter);
             }
         }
@@ -1051,48 +545,58 @@
             this.subquery = subquery;
             return this;
         }
-        
+
         @Override
         public String toString() {
-            if( ! StringUtils.isEmpty(passthrough) ) {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
+            if (!StringUtils.isEmpty(passthrough)) {
                 return passthrough;
             }
-            if( ! StringUtils.isEmpty(subquery) ) {
+            if (!StringUtils.isEmpty(subquery)) {
                 return "( " + this.subquery + ") as _subquery_alias_ ";
             }
-            return this.tableName.toString();
+            return this.tableName.toString(formatter);
         }
 
     }
 
-    public class SelectColumnBuilderBase implements SelectColumnBuilder {
+    public class SelectColumnBuilderBase
+            extends AbstractStatementPart
+            implements SelectColumnBuilder {
 
         private Variable name = null;
         private String alias = null;
         private Value value = null;
         private boolean asGeometry = false;
-        
+
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.name != null ) {
+            if (this.name != null) {
                 this.name.accept(visitor, filter);
             }
-            if( this.value != null ) {
+            if (this.value != null) {
                 this.value.accept(visitor, filter);
             }
         }
 
         @Override
         public SelectColumnBuilder name(String name) {
-            String quote = config.getString(Config.quote_for_identifiers);
+            String quote = quote_for_identifiers();
             if (name.startsWith(quote)) {
                 // Remove quotes
                 name = name.substring(1, name.length() - 1);
             }
-            this.name = variable(name);
+            this.name = expression().variable(name);
             this.value = null;
             this.asGeometry = false;
             return this;
@@ -1101,17 +605,17 @@
         @Override
         public SelectColumnBuilder all() {
             this.name = null;
-            this.value = custom("*");
+            this.value = expression().custom("*");
             this.asGeometry = false;
             return this;
         }
-        
+
         @Override
         public SelectColumnBuilder as_geometry() {
             this.asGeometry = true;
             return this;
         }
-       
+
         @Override
         public SelectColumnBuilder value(Value value) {
             this.value = value;
@@ -1127,14 +631,14 @@
 
         @Override
         public String getName() {
-            return this.name.getName();
+            return this.name.name();
         }
-        
+
         @Override
         public String getAlias() {
             return this.alias;
         }
-        
+
         @Override
         public String getValue() {
             return this.alias;
@@ -1142,36 +646,47 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
-            if( this.asGeometry ) {
-                builder.append(getAsGeometry(this.name).toString());
+            if (this.asGeometry) {
+                builder.append(expression().ST_AsBinary(this.name).toString(formatter));
             } else {
-                if( this.name != null ) {
-                    builder.append(this.name.toString());
+                if (this.name != null) {
+                    builder.append(this.name.toString(formatter));
                 } else {
-                    builder.append(this.value.toString());
+                    builder.append(this.value.toString(formatter));
                 }
             }
-            if( this.alias != null ) {
+            if (this.alias != null) {
                 builder.append(" AS ");
-                builder.append(identifier(this.alias));
+                builder.append(as_identifier(this.alias));
             }
             return builder.toString();
         }
     }
 
-    public class OrderByBuilderBase implements OrderByBuilder {
+    public class OrderByBuilderBase
+            extends AbstractStatementPart
+            implements OrderByBuilder {
+
         protected String value;
         protected String custom;
         protected boolean ascending;
-        
+
         public OrderByBuilderBase() {
             this.ascending = true;
         }
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
         }
@@ -1208,18 +723,28 @@
 
         @Override
         public String toString() {
-            if( !StringUtils.isEmpty(this.custom) ) {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
+            if (!StringUtils.isEmpty(this.custom)) {
                 return this.custom;
             }
-            if( this.ascending ) {
-                return identifier(this.value) + " ASC";
+            if (this.ascending) {
+                return as_identifier(this.value) + " ASC";
             }
-            return identifier(this.value) + " DESC";
+            return as_identifier(this.value) + " DESC";
         }
     }
-    
-    public class SelectBuilderBase implements SelectBuilder {
 
+    public class SelectBuilderBase
+            extends AbstractStatement
+            implements SelectBuilder {
+
         protected FromBuilder from;
         protected ExpressionBuilder where;
         protected long limit = -1;
@@ -1235,21 +760,21 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
             for (SelectColumnBuilder column : columns) {
-                column.accept(visitor,filter);
+                column.accept(visitor, filter);
             }
-            if( this.has_from() ) {
-                this.from.accept(visitor,filter);
+            if (this.has_from()) {
+                this.from.accept(visitor, filter);
             }
-            if( this.has_where() ) {
-                this.where.accept(visitor,filter);
+            if (this.has_where()) {
+                this.where.accept(visitor, filter);
             }
-            if( this.has_order_by() ) {
+            if (this.has_order_by()) {
                 for (OrderByBuilder order : order_by) {
-                    order.accept(visitor,filter);
+                    order.accept(visitor, filter);
                 }
             }
         }
@@ -1259,7 +784,7 @@
             this.distinct = true;
             return this;
         }
-        
+
         @Override
         public SelectColumnBuilder column() {
             SelectColumnBuilder builder = createSelectColumnBuilder();
@@ -1270,7 +795,7 @@
         @Override
         public boolean has_column(String name) {
             for (SelectColumnBuilder column : columns) {
-                if( name.equals(column.getName()) ) {
+                if (name.equals(column.getName())) {
                     return true;
                 }
             }
@@ -1289,7 +814,7 @@
         public boolean has_from() {
             return this.from != null;
         }
-        
+
         @Override
         public ExpressionBuilder where() {
             if (this.where == null) {
@@ -1300,12 +825,12 @@
 
         @Override
         public boolean has_where() {
-            if( this.where == null ) {
+            if (this.where == null) {
                 return false;
             }
-            return this.where.getValue() != null;
+            return this.where.value() != null;
         }
-        
+
         @Override
         public SelectBuilder limit(long limit) {
             this.limit = limit;
@@ -1314,7 +839,7 @@
 
         @Override
         public SelectBuilder limit(Long limit) {
-            if( limit == null ) {
+            if (limit == null) {
                 this.limit = 0;
             } else {
                 this.limit = limit;
@@ -1340,7 +865,7 @@
 
         @Override
         public OrderByBuilder order_by() {
-            if( this.order_by == null ) {
+            if (this.order_by == null) {
                 this.order_by = new ArrayList<>();
             }
             OrderByBuilder order = createOrderByBuilder();
@@ -1350,17 +875,17 @@
 
         @Override
         public boolean has_order_by() {
-            if( this.order_by == null ) {
+            if (this.order_by == null) {
                 return false;
             }
             return !this.order_by.isEmpty();
         }
-        
+
         protected boolean isValid(StringBuilder message) {
-            if( message == null ) {
+            if (message == null) {
                 message = new StringBuilder();
             }
-            if( this.has_offset() && !this.has_order_by() ) {
+            if (this.has_offset() && !this.has_order_by()) {
                 // Algunos gestores de BBDD requieren que se especifique un
                 // orden para poder usar OFFSET. Como eso parece buena idea para
                 // asegurar que siempre tengamos los mismo resultados, lo exijimos
@@ -1370,15 +895,23 @@
             }
             return true;
         }
-        
+
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
-            if( !this.isValid(builder) ) {
+            if (!this.isValid(builder)) {
                 throw new IllegalStateException(builder.toString());
             }
             builder.append("SELECT ");
-            if( this.distinct ) {
+            if (this.distinct) {
                 builder.append("DISTINCT ");
             }
             boolean first = true;
@@ -1388,19 +921,19 @@
                 } else {
                     builder.append(", ");
                 }
-                builder.append(column.toString());
+                builder.append(column.toString(formatter));
             }
 
-            if ( this.has_from() ) {
+            if (this.has_from()) {
                 builder.append(" FROM ");
-                builder.append(this.from.toString());
+                builder.append(this.from.toString(formatter));
             }
-            if ( this.has_where() ) {
+            if (this.has_where()) {
                 builder.append(" WHERE ");
-                builder.append(this.where.toString());
+                builder.append(this.where.toString(formatter));
             }
-            
-            if( this.has_order_by() ) {
+
+            if (this.has_order_by()) {
                 builder.append(" ORDER BY ");
                 first = true;
                 for (OrderByBuilder item : this.order_by) {
@@ -1409,15 +942,15 @@
                     } else {
                         builder.append(", ");
                     }
-                    builder.append(item.toString());                    
-                }   
+                    builder.append(item.toString(formatter));
+                }
             }
-            
-            if ( this.has_limit() ) {
+
+            if (this.has_limit()) {
                 builder.append(" LIMIT ");
                 builder.append(this.limit);
             }
-            if ( this.has_offset() ) {
+            if (this.has_offset()) {
                 builder.append(" OFFSET ");
                 builder.append(this.offset);
             }
@@ -1426,13 +959,15 @@
         }
     }
 
-    public class DropTableBuilderBase implements DropTableBuilder {
+    public class DropTableBuilderBase
+            extends AbstractStatement
+            implements DropTableBuilder {
 
         protected TableNameBuilder table;
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1440,18 +975,26 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            this.table.accept(visitor,filter);
+            this.table.accept(visitor, filter);
         }
-        
+
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
-            for (String sql : toStrings()) {
-                if( StringUtils.isEmpty(sql) ) {
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
                     continue;
                 }
                 if (first) {
@@ -1466,29 +1009,34 @@
 
         @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             List<String> sqls = new ArrayList<>();
 
             sqls.add(
                     MessageFormat.format(
-                            config.getString(SQLConfig.DROP_TABLE_table),
-                            this.table.toString()
+                            STMT_DROP_TABLE_table,
+                            this.table.toString(formatter)
                     )
             );
             String sql;
-            if( config.has_functionality(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table) ) {
+            if (!StringUtils.isBlank(STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table)) {
                 if (this.table.has_schema()) {
                     sql = MessageFormat.format(
-                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table),
-                            string(this.table.getSchema()),
-                            string(this.table.getName())
+                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table,
+                            as_string(this.table.getSchema()),
+                            as_string(this.table.getName())
                     );
                 } else {
                     sql = MessageFormat.format(
-                            config.getString(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table),
-                            identifier(this.table.getName())
+                            STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table,
+                            as_identifier(this.table.getName())
                     );
                 }
-                if( !StringUtils.isEmpty(sql) ) {
+                if (!StringUtils.isEmpty(sql)) {
                     sqls.add(sql);
                 }
             }
@@ -1496,7 +1044,10 @@
         }
     }
 
-    public class GrantRoleBuilderBase implements GrantRoleBuilder {
+    public class GrantRoleBuilderBase
+            extends AbstractStatementPart
+            implements GrantRoleBuilder {
+
         protected TableNameBuilder table;
         protected String role;
         protected Set<Privilege> privileges;
@@ -1512,16 +1063,16 @@
             privileges.add(privilege);
             return this;
         }
-        
+
         @Override
         public GrantRoleBuilder select() {
-             privileges.add(Privilege.SELECT);
+            privileges.add(Privilege.SELECT);
             return this;
         }
 
         @Override
         public GrantRoleBuilder update() {
-             privileges.add(Privilege.UPDATE);
+            privileges.add(Privilege.UPDATE);
             return this;
         }
 
@@ -1562,7 +1113,7 @@
         }
 
         protected String getPrivilegeName(Privilege privilege) {
-            switch(privilege) {
+            switch (privilege) {
                 case DELETE:
                     return "DELETE";
                 case INSERT:
@@ -1582,9 +1133,17 @@
                     return "ALL";
             }
         }
-        
+
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
             for (Privilege privilege : privileges) {
@@ -1593,30 +1152,32 @@
                 } else {
                     builder.append(", ");
                 }
-                builder.append( this.getPrivilegeName(privilege));
+                builder.append(this.getPrivilegeName(privilege));
             }
             String sql = MessageFormat.format(
-                    config.getString(SQLConfig.GRANT_privileges_ON_table_TO_role),
+                    STMT_GRANT_privileges_ON_table_TO_role,
                     builder.toString(),
-                    table.toString(),
+                    table.toString(formatter),
                     role
             );
             return sql;
         }
     }
-    
-    public class GrantBuilderBase implements GrantBuilder {
 
+    public class GrantBuilderBase
+            extends AbstractStatement
+            implements GrantBuilder {
+
         protected TableNameBuilder table;
         protected Map<String, GrantRoleBuilder> roles;
 
         public GrantBuilderBase() {
             this.roles = new HashMap<>();
         }
-        
+
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1624,18 +1185,18 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table!= null ) {
-                this.table.accept(visitor,filter);
+            if (this.table != null) {
+                this.table.accept(visitor, filter);
             }
         }
-        
+
         @Override
         public GrantRoleBuilder role(String role) {
             GrantRoleBuilder roleBuilder = this.roles.get(role);
-            if( roleBuilder == null ) {
+            if (roleBuilder == null) {
                 roleBuilder = createGrantRoleBuilder(this.table(), role);
                 this.roles.put(role, roleBuilder);
             }
@@ -1644,10 +1205,18 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
-            for (String sql : toStrings()) {
-                if( StringUtils.isEmpty(sql) ) {
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
                     continue;
                 }
                 if (first) {
@@ -1662,16 +1231,23 @@
 
         @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             List<String> sqls = new ArrayList<>();
             for (GrantRoleBuilder role : roles.values()) {
-                sqls.add(role.toString());
+                sqls.add(role.toString(formatter));
             }
             return sqls;
         }
     }
 
-    public class UpdateColumnBuilderBase extends InsertColumnBuilderBase implements UpdateColumnBuilder {
-        
+    public class UpdateColumnBuilderBase
+            extends InsertColumnBuilderBase
+            implements UpdateColumnBuilder {
+
         public UpdateColumnBuilderBase() {
             super();
         }
@@ -1685,11 +1261,13 @@
         public UpdateColumnBuilder with_value(Value value) {
             return (UpdateColumnBuilder) super.with_value(value);
         }
-        
+
     }
-    
-    public class UpdateBuilderBase implements UpdateBuilder {
 
+    public class UpdateBuilderBase
+            extends AbstractStatement
+            implements UpdateBuilder {
+
         protected ExpressionBuilder where;
         protected List<UpdateColumnBuilder> columns;
         protected TableNameBuilder table;
@@ -1700,16 +1278,16 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
             for (UpdateColumnBuilder column : columns) {
                 column.accept(visitor, filter);
             }
-            if( this.has_where() ) {
+            if (this.has_where()) {
                 this.where.accept(visitor, filter);
             }
         }
@@ -1724,7 +1302,7 @@
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1736,7 +1314,7 @@
             this.columns.add(column);
             return column;
         }
-        
+
         @Override
         public boolean has_where() {
             return this.where != null;
@@ -1744,6 +1322,14 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             /*
              * UPDATE [ ONLY ] table [ [ AS ] alias ] SET { column = { expression |
              * DEFAULT } | ( column [, ...] ) = ( { expression | DEFAULT } [, ...] )
@@ -1759,23 +1345,23 @@
                 } else {
                     columnsAndValues.append(", ");
                 }
-                columnsAndValues.append(identifier(column.getName()));
+                columnsAndValues.append(as_identifier(column.getName()));
                 columnsAndValues.append(" = ");
-                columnsAndValues.append(column.getValue().toString());
+                columnsAndValues.append(column.getValue().toString(formatter));
             }
-            
+
             String sql;
-            if ( this.has_where() ) {
+            if (this.has_where()) {
                 sql = MessageFormat.format(
-                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion),
-                        this.table.toString(),
+                        STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion,
+                        this.table.toString(formatter),
                         columnsAndValues.toString(),
-                        this.where.toString()
+                        this.where.toString(formatter)
                 );
             } else {
                 sql = MessageFormat.format(
-                        config.getString(SQLConfig.UPDATE_table_SET_columnsAndValues),
-                        this.table.toString(),
+                        STMT_UPDATE_table_SET_columnsAndValues,
+                        this.table.toString(formatter),
                         columnsAndValues.toString()
                 );
             }
@@ -1783,7 +1369,9 @@
         }
     }
 
-    public class DeleteBuilderBase implements DeleteBuilder {
+    public class DeleteBuilderBase
+            extends AbstractStatement
+            implements DeleteBuilder {
 
         protected ExpressionBuilder where;
         protected TableNameBuilder table;
@@ -1793,13 +1381,13 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
-            if( this.has_where() ) {
+            if (this.has_where()) {
                 this.where.accept(visitor, filter);
             }
         }
@@ -1814,7 +1402,7 @@
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1827,28 +1415,38 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             /*
              * DELETE FROM table_name
              * WHERE some_column=some_value; 
              */
             String sql;
-            if( this.has_where() ) {
+            if (this.has_where()) {
                 sql = MessageFormat.format(
-                        config.getString(SQLConfig.DELETE_FROM_table_WHERE_expresion),
-                        this.table.toString(),
-                        this.where.toString()
+                        STMT_DELETE_FROM_table_WHERE_expresion,
+                        this.table.toString(formatter),
+                        this.where.toString(formatter)
                 );
             } else {
                 sql = MessageFormat.format(
-                        config.getString(SQLConfig.DELETE_FROM_table),
-                        this.table.toString()
+                        STMT_DELETE_FROM_table,
+                        this.table.toString(formatter)
                 );
             }
             return sql;
         }
     }
 
-    public class CreateIndexBuilderBase implements CreateIndexBuilder {
+    public class CreateIndexBuilderBase
+            extends AbstractStatement
+            implements CreateIndexBuilder {
 
         protected boolean ifNotExist = false;
         protected boolean isUnique = false;
@@ -1856,11 +1454,11 @@
         protected boolean isSpatial = false;
         protected TableNameBuilder table;
         protected final List<String> columns;
-        
+
         public CreateIndexBuilderBase() {
             this.columns = new ArrayList<>();
         }
-        
+
         @Override
         public CreateIndexBuilder unique() {
             this.isUnique = true;
@@ -1893,7 +1491,7 @@
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1901,35 +1499,66 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
         }
-        
+
         @Override
+        public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
+            StringBuilder builder = new StringBuilder();
+            boolean first = true;
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
+                    continue;
+                }
+                if (first) {
+                    first = false;
+                } else {
+                    builder.append("; ");
+                }
+                builder.append(sql);
+            }
+            return builder.toString();
+        }
+
+        @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             StringBuilder builder = new StringBuilder();
             builder.append("CREATE ");
-            if( this.isUnique ) {
+            if (this.isUnique) {
                 builder.append("UNIQUE ");
             }
             builder.append("INDEX ");
-            if( this.ifNotExist ) {
+            if (this.ifNotExist) {
                 builder.append("IF NOT EXISTS ");
             }
-            builder.append(identifier(this.indexName));
+            builder.append(as_identifier(this.indexName));
             builder.append(" ON ");
-            builder.append(this.table.toString());
-            if( this.isSpatial ) {
+            builder.append(this.table.toString(formatter));
+            if (this.isSpatial) {
                 builder.append(" USING GIST ");
             }
             builder.append(" ( ");
             boolean is_first_column = true;
-            for( String column : this.columns) {
-                if( is_first_column ) {
+            for (String column : this.columns) {
+                if (is_first_column) {
                     is_first_column = false;
                 } else {
                     builder.append(", ");
@@ -1937,21 +1566,23 @@
                 builder.append(column);
             }
             builder.append(" )");
-            
+
             List<String> sqls = new ArrayList<>();
             sqls.add(builder.toString());
             return sqls;
         }
 
     }
-    
-    public class AlterTableBuilderBase implements AlterTableBuilder {
 
+    public class AlterTableBuilderBase
+            extends AbstractStatement
+            implements AlterTableBuilder {
+
         protected TableNameBuilder table;
         protected List<String> drops;
         protected List<ColumnDescriptor> adds;
         protected List<ColumnDescriptor> alters;
-        protected List<Pair<String,String>> renames;
+        protected List<Pair<String, String>> renames;
 
         public AlterTableBuilderBase() {
             this.drops = new ArrayList<>();
@@ -1962,25 +1593,25 @@
 
         @Override
         public boolean isEmpty() {
-            return this.drops.isEmpty() && 
-                this.adds.isEmpty() && 
-                this.alters.isEmpty() && 
-                this.renames.isEmpty();
+            return this.drops.isEmpty()
+                    && this.adds.isEmpty()
+                    && this.alters.isEmpty()
+                    && this.renames.isEmpty();
         }
-        
+
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
         }
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -1991,11 +1622,11 @@
             this.drops.add(columnName);
             return this;
         }
-        
+
         @Override
         public AlterTableBuilder add_column(FeatureAttributeDescriptor fad) {
-            this.adds.add(column(fad).getDescriptor());
-            return this;            
+            this.adds.add(new ColumnDescriptorBase(fad));
+            return this;
         }
 
         @Override
@@ -2009,7 +1640,7 @@
 
         @Override
         public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
@@ -2018,19 +1649,19 @@
 
         @Override
         public AlterTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.adds.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
             return this;
         }
-        
+
         @Override
         public AlterTableBuilder alter_column(FeatureAttributeDescriptor fad) {
-            this.alters.add(column(fad).getDescriptor());
-            return this;            
+            this.alters.add(new ColumnDescriptorBase(fad));
+            return this;
         }
-        
+
         @Override
         public AlterTableBuilder alter_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
             if (isPk || isAutomatic) {
@@ -2042,7 +1673,7 @@
 
         @Override
         public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
@@ -2051,7 +1682,7 @@
 
         @Override
         public AlterTableBuilder alter_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.alters.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
@@ -2066,10 +1697,18 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
-            for (String sql : toStrings()) {
-                if( StringUtils.isEmpty(sql) ) {
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
                     continue;
                 }
                 if (first) {
@@ -2084,36 +1723,41 @@
 
         @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             List<String> sqls = new ArrayList<>();
-            if( this.isEmpty() ) {
+            if (this.isEmpty()) {
                 return sqls;
             }
             for (String column : drops) {
                 StringBuilder builder = new StringBuilder();
                 builder.append("ALTER TABLE ");
-                builder.append(this.table.toString());
+                builder.append(this.table.toString(formatter));
                 builder.append(" DROP COLUMN IF EXISTS ");
-                builder.append(identifier(column)); 
+                builder.append(as_identifier(column));
                 sqls.add(builder.toString());
             }
             for (ColumnDescriptor column : adds) {
                 StringBuilder builder = new StringBuilder();
                 builder.append("ALTER TABLE ");
-                builder.append(this.table.toString());
+                builder.append(this.table.toString(formatter));
                 builder.append(" ADD COLUMN ");
-                builder.append(identifier(column.getName())); 
+                builder.append(as_identifier(column.getName()));
                 builder.append(" ");
-                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
+                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
                     builder.append(" SERIAL");
                 } else {
                     builder.append(
-                        sqltype(
-                            column.getType(), 
-                            column.getPrecision(), 
-                            column.getSize(),
-                            column.getGeometryType(),
-                            column.getGeometrySubtype()
-                        )
+                            sqltype(
+                                    column.getType(),
+                                    column.getPrecision(),
+                                    column.getSize(),
+                                    column.getGeometryType(),
+                                    column.getGeometrySubtype()
+                            )
                     );
                 }
                 if (column.getDefaultValue() == null) {
@@ -2138,21 +1782,21 @@
             for (ColumnDescriptor column : alters) {
                 StringBuilder builder = new StringBuilder();
                 builder.append("ALTER TABLE ");
-                builder.append(this.table.toString());
+                builder.append(this.table.toString(formatter));
                 builder.append(" ALTER COLUMN ");
-                builder.append(identifier(column.getName())); 
+                builder.append(as_identifier(column.getName()));
                 builder.append(" SET DATA TYPE ");
-                if( column.getType() == DataTypes.INT && column.isAutomatic() ) {
+                if (column.getType() == DataTypes.INT && column.isAutomatic()) {
                     builder.append(" SERIAL");
                 } else {
                     builder.append(
-                        sqltype(
-                            column.getType(), 
-                            column.getPrecision(), 
-                            column.getSize(),
-                            column.getGeometryType(),
-                            column.getGeometrySubtype()
-                        )
+                            sqltype(
+                                    column.getType(),
+                                    column.getPrecision(),
+                                    column.getSize(),
+                                    column.getGeometryType(),
+                                    column.getGeometrySubtype()
+                            )
                     );
                 }
                 if (column.getDefaultValue() == null) {
@@ -2168,14 +1812,14 @@
                 }
                 sqls.add(builder.toString());
             }
-            for (Pair<String,String> pair : renames) {
+            for (Pair<String, String> pair : renames) {
                 StringBuilder builder = new StringBuilder();
                 builder.append("ALTER TABLE ");
-                builder.append(this.table.toString());
+                builder.append(this.table.toString(formatter));
                 builder.append(" RENAME COLUMN ");
-                builder.append(identifier(pair.getLeft())); 
+                builder.append(as_identifier(pair.getLeft()));
                 builder.append(" TO ");
-                builder.append(identifier(pair.getRight())); 
+                builder.append(as_identifier(pair.getRight()));
                 sqls.add(builder.toString());
             }
             return sqls;
@@ -2183,7 +1827,9 @@
 
     }
 
-    public class CreateTableBuilderBase implements CreateTableBuilder {
+    public class CreateTableBuilderBase
+            extends AbstractStatement
+            implements CreateTableBuilder {
 
         protected TableNameBuilder table;
         protected List<ColumnDescriptor> columns;
@@ -2194,17 +1840,17 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
         }
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -2212,13 +1858,13 @@
 
         @Override
         public CreateTableBuilderBase add_column(FeatureAttributeDescriptor fad) {
-            this.columns.add(column(fad).getDescriptor());
-            return this;            
+            this.columns.add(new ColumnDescriptorBase(fad));
+            return this;
         }
 
         @Override
         public CreateTableBuilderBase add_column(String columnName, int type, int type_p, int type_s, boolean isPk, boolean isIndexed, boolean allowNulls, boolean isAutomatic, Object defaultValue) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             if (isPk || isAutomatic) {
@@ -2230,7 +1876,7 @@
 
         @Override
         public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, IProjection proj, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, proj, isIndexed, allowNulls));
@@ -2239,7 +1885,7 @@
 
         @Override
         public CreateTableBuilder add_geometry_column(String columnName, int type, int subtype, Object srsdbcode, boolean isIndexed, boolean allowNulls) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 throw new IllegalArgumentException("Argument 'columnName' can't be empty.");
             }
             this.columns.add(new ColumnDescriptorBase(columnName, type, subtype, srsdbcode, isIndexed, allowNulls));
@@ -2248,23 +1894,31 @@
 
         @Override
         public ColumnDescriptor getColumnDescriptor(String columnName) {
-            if( StringUtils.isEmpty(columnName) ) {
+            if (StringUtils.isEmpty(columnName)) {
                 return null;
             }
             for (ColumnDescriptor column : columns) {
-                if( columnName.equals(column.getName()) ) {
+                if (columnName.equals(column.getName())) {
                     return column;
                 }
             }
             return null;
         }
-                
+
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
-            for (String sql : toStrings()) {
-                if( StringUtils.isEmpty(sql) ) {
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
                     continue;
                 }
                 if (first) {
@@ -2279,6 +1933,11 @@
 
         @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             List<String> sqls = new ArrayList<>();
             /**
              * CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE
@@ -2308,7 +1967,7 @@
             StringBuilder builder = new StringBuilder();
 
             builder.append("CREATE TABLE ");
-            builder.append(this.table.toString());
+            builder.append(this.table.toString(formatter));
             builder.append(" (");
             boolean first = true;
             for (ColumnDescriptor column : columns) {
@@ -2317,14 +1976,21 @@
                 } else {
                     builder.append(", ");
                 }
-                builder.append(identifier(column.getName()));
+                builder.append(as_identifier(column.getName()));
                 builder.append(" ");
-                if( column.isAutomatic() && column.getType() == DataTypes.INT ) {
+                if (column.isAutomatic() && column.getType() == DataTypes.INT) {
                     builder.append("SERIAL");
-                } else if( column.isAutomatic() && column.getType() == DataTypes.LONG ) {
+                } else if (column.isAutomatic() && column.getType() == DataTypes.LONG) {
                     builder.append("BIGSERIAL");
                 } else {
-                    builder.append(sqltype(column.getType(), column.getPrecision(), column.getSize()));
+                    builder.append(sqltype(
+                            column.getType(),
+                            column.getPrecision(),
+                            column.getSize(),
+                            column.getGeometryType(),
+                            column.getGeometrySubtype()
+                    )
+                    );
                 }
                 if (column.getDefaultValue() == null) {
                     if (column.allowNulls()) {
@@ -2350,29 +2016,32 @@
         }
     }
 
-    public class InsertColumnBuilderBase implements InsertColumnBuilder {
+    public class InsertColumnBuilderBase
+            extends AbstractStatement
+            implements InsertColumnBuilder {
+
         protected Variable name;
         protected Value value;
-        
+
         public InsertColumnBuilderBase() {
         }
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.name != null ) {
+            if (this.name != null) {
                 this.name.accept(visitor, filter);
             }
-            if( this.value != null ) {
+            if (this.value != null) {
                 this.value.accept(visitor, filter);
             }
         }
 
         @Override
         public InsertColumnBuilder name(String name) {
-            this.name = variable(name);
+            this.name = expression().variable(name);
             return this;
         }
 
@@ -2381,25 +2050,35 @@
             this.value = value;
             return this;
         }
-        
+
         @Override
         public String getName() {
-            return this.name.getName();
+            return this.name.name();
         }
-        
+
         @Override
         public Value getValue() {
             return this.value;
         }
-        
+
         @Override
         public String toString() {
-            return this.value.toString();
+            return this.toString(formatter());
         }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
+            return this.value.toString(formatter);
+        }
     }
-    
-    public class InsertBuilderBase implements InsertBuilder {
 
+    public class InsertBuilderBase
+            extends AbstractStatement
+            implements InsertBuilder {
+
         protected List<InsertColumnBuilder> columns;
         protected TableNameBuilder table;
 
@@ -2409,10 +2088,10 @@
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
             for (InsertColumnBuilder column : columns) {
@@ -2422,7 +2101,7 @@
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -2437,6 +2116,14 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             /*
              * INSERT INTO table [ ( column [, ...] ) ] { DEFAULT VALUES | VALUES (
              * { expression | DEFAULT } [, ...] ) [, ...] | query } [ RETURNING * |
@@ -2444,7 +2131,7 @@
              */
             StringBuilder builderColumns = new StringBuilder();
             StringBuilder builderValues = new StringBuilder();
-            
+
             boolean first = true;
             for (InsertColumnBuilder column : columns) {
                 if (first) {
@@ -2452,7 +2139,7 @@
                 } else {
                     builderColumns.append(", ");
                 }
-                builderColumns.append(identifier(column.getName()));
+                builderColumns.append(as_identifier(column.getName()));
             }
             first = true;
             for (InsertColumnBuilder column : columns) {
@@ -2461,12 +2148,12 @@
                 } else {
                     builderValues.append(", ");
                 }
-                builderValues.append(column.toString());
+                builderValues.append(column.toString(formatter));
             }
-            
+
             String sql = MessageFormat.format(
-                    config.getString(SQLConfig.INSERT_INTO_table_columns_VALUES_values),
-                    this.table.toString(),
+                    STMT_INSERT_INTO_table_columns_VALUES_values,
+                    this.table.toString(formatter),
                     builderColumns.toString(),
                     builderValues.toString()
             );
@@ -2475,23 +2162,25 @@
         }
     }
 
-    public class UpdateTableStatisticsBuilderBase implements UpdateTableStatisticsBuilder {
+    public class UpdateTableStatisticsBuilderBase
+            extends AbstractStatement
+            implements UpdateTableStatisticsBuilder {
 
         protected TableNameBuilder table;
 
         @Override
         public void accept(Visitor visitor, VisitorFilter filter) {
-            if( filter.accept(this) ) {
+            if (filter.accept(this)) {
                 visitor.visit(this);
             }
-            if( this.table != null ) {
+            if (this.table != null) {
                 this.table.accept(visitor, filter);
             }
         }
 
         @Override
         public TableNameBuilder table() {
-            if( table == null ) {
+            if (table == null) {
                 table = createTableNameBuilder();
             }
             return table;
@@ -2499,10 +2188,18 @@
 
         @Override
         public String toString() {
+            return this.toString(formatter());
+        }
+
+        @Override
+        public String toString(Formatter<Value> formatter) {
+            if (formatter.canApply(this)) {
+                return formatter.format(this);
+            }
             StringBuilder builder = new StringBuilder();
             boolean first = true;
-            for (String sql : toStrings()) {
-                if( StringUtils.isEmpty(sql) ) {
+            for (String sql : toStrings(formatter)) {
+                if (StringUtils.isEmpty(sql)) {
                     continue;
                 }
                 if (first) {
@@ -2517,14 +2214,19 @@
 
         @Override
         public List<String> toStrings() {
+            return this.toStrings(formatter());
+        }
+
+        @Override
+        public List<String> toStrings(Formatter formatter) {
             List<String> sqls = new ArrayList<>();
-            
-            if( config.has_functionality(SQLConfig.UPDATE_TABLE_STATISTICS_table) ) {
+
+            if (!StringUtils.isBlank(STMT_UPDATE_TABLE_STATISTICS_table)) {
                 String sql = MessageFormat.format(
-                        config.getString(SQLConfig.UPDATE_TABLE_STATISTICS_table),
-                        table.toString()
-                    );
-                if( !StringUtils.isEmpty(sql) ) {
+                        STMT_UPDATE_TABLE_STATISTICS_table,
+                        table.toString(formatter)
+                );
+                if (!StringUtils.isEmpty(sql)) {
                     sqls.add(sql);
                 }
             }
@@ -2532,650 +2234,211 @@
         }
     }
 
+    protected ExpressionBuilder expressionBuilder;
 
-    private static class ParametersBase extends ArrayList<Parameter> implements Parameters {
+    protected String defaultSchema;
+    protected boolean supportSchemas;
+    protected boolean hasSpatialFunctions;
+    protected GeometrySupportType geometrySupportType;
+    protected boolean allowAutomaticValues;
 
-        private static final long serialVersionUID = -2188534574151780470L;
+    private static Map<Pair<Integer, Integer>, String> sqlgeometrytypes = null;
 
-        public ParametersBase() {
-            super();
-        }
+    protected String constant_true = "(1=1)";
+    protected String constant_false = "(1=1)";
 
-        public ParametersBase(Collection parameters) {
-            super(parameters);
-        }
+    protected String type_boolean = "BOOLEAN";
+    protected String type_byte = "TINYINT";
+    protected String type_bytearray = "BYTEA";
+    protected String type_geometry = "TEXT";
+    protected String type_char = "CHARACTER(1)";
+    protected String type_date = "DATE";
+    protected String type_double = "DOUBLE PRECISION"; //float con 53 bits de mantisa, float(54)
+    protected String type_numeric_p = "NUMERIC({0})";
+    protected String type_numeric_ps = "NUMERIC({0},{1})";
+    protected String type_bigdecimal = "NUMERIC({0},{1})";
+    protected String type_float = "REAL"; //float con 24 bits de mantisa, float(24)
+    protected String type_int = "INT";
+    protected String type_long = "BIGINT";
+    protected String type_string = "TEXT";
+    protected String type_string_p = "VARCHAR({0})";
+    protected String type_time = "TIME";
+    protected String type_timestamp = "TIMESTAMP";
+    protected String type_version = "VARCHAR(30)";
+    protected String type_URI = "TEXT";
+    protected String type_URL = "TEXT";
+    protected String type_FILE = "TEXT";
+    protected String type_FOLDER = "TEXT";
 
-        @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;
-        }
+    protected String STMT_DELETE_FROM_table_WHERE_expresion = "DELETE FROM {0} WHERE {1}";
+    protected String STMT_DELETE_FROM_table = "DELETE FROM {0}";
+    protected String STMT_INSERT_INTO_table_columns_VALUES_values = "INSERT INTO {0} ( {1} ) VALUES ( {2} )";
+    protected String STMT_UPDATE_TABLE_STATISTICS_table = "VACUUM ANALYZE {0}";
+    protected String STMT_DROP_TABLE_table = "DROP TABLE {0}";
+    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}";
+    protected String STMT_DELETE_GEOMETRY_COLUMN_FROM_TABLE_table = "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}";
+    protected String STMT_UPDATE_table_SET_columnsAndValues_WHERE_expresion = "UPDATE {0} SET {1} WHERE {2}";
+    protected String STMT_UPDATE_table_SET_columnsAndValues = "UPDATE {0} SET {1}";
+    protected String STMT_GRANT_privileges_ON_table_TO_role = "GRANT {0} ON {1} TO {2}";
 
-        
-        @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();
-        }
-    }
-
-    protected Value value;
-    protected Config config;
-  
     public SQLBuilderBase() {
-        
-        this.config = new ConfigBase();
-        this.value = null;
-        
-        config.set(SQLConfig.has_spatial_functions, false);
-        config.set(SQLConfig.support_schemas, true);
-        config.set(SQLConfig.constant_true, "(1=1)");
-        config.set(SQLConfig.constant_false, "(1=2)");
-        config.set(SQLConfig.quote_for_identifiers, "\"");
-        config.set(SQLConfig.quote_for_strings, "'");
-        config.set(SQLConfig.geometry_type_support, GeometrySupportType.WKT);
-        config.set(SQLConfig.group, "( {0} )");
+        this.expressionBuilder = ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
 
-        config.set(SQLConfig.ST_SRID, "ST_SRID({0})");
-        config.set(SQLConfig.ST_AsText, "ST_AsText({0})");
-        config.set(SQLConfig.ST_AsBinary, "ST_AsBinary({0})");
-        config.set(SQLConfig.ST_AsEWKB, "ST_AsEWKB({0})");
-        config.set(SQLConfig.ST_Contains, "ST_Contains(({0}), ({1}))");
-        config.set(SQLConfig.ST_Crosses, "ST_Crosses(({0}), ({1}))");
-        config.set(SQLConfig.ST_Disjoint, "ST_Disjoint(({0}), ({1}))");
-        config.set(SQLConfig.ST_Equals, "ST_Equals(({0}), ({1}))");
-        config.set(SQLConfig.ST_IsClosed, "ST_IsClosed({0})");
-        config.set(SQLConfig.ST_Overlaps, "ST_Overlaps(({0}), ({1}))");
-        config.set(SQLConfig.ST_Touches, "ST_Touches(({0}), ({1}))");
-        config.set(SQLConfig.ST_Within, "ST_Within(({0}), ({1}))");
-        config.set(SQLConfig.ST_Envelope, "ST_Envelope({0})");
-        config.set(SQLConfig.ST_Intersects, "ST_Intersects(({0}), ({1}))");
-        config.set(SQLConfig.ST_GeomFromText, "ST_GeomFromText({0}, ({1}))");
-        config.set(SQLConfig.ST_GeomFromWKB, "ST_GeomFromWKB(({0}), ({1}))");
-        config.set(SQLConfig.ST_GeomFromEWKB, "ST_GeomFromEWKB(({0}), ({1}))");
+        this.hasSpatialFunctions = false;
+        this.supportSchemas = true;
+        this.geometrySupportType = GeometrySupportType.WKT;
 
-        // Por defecto no esta disponible la funcion ST_Simplify
-        // El proveedor que la soporte que la defina.
-        // config.set(SQLConfig.ST_Simplify, "ST_Simplify(({0}), ({1}))");
-        config.remove_functionality(SQLConfig.ST_Simplify);
+        this.defaultSchema = "public";
+        this.allowAutomaticValues = true;
 
-        config.set(SQLConfig.lcase, "LCASE({0})");
-        config.set(SQLConfig.ucase, "UCASE({0})");
-        config.set(SQLConfig.isNull, "( ({0}) IS NULL )");
-        config.set(SQLConfig.notIsNull, "( ({0}) NOT IS NULL )");
-        config.set(SQLConfig.operator_not, "( NOT ({0}) )");
-
-        config.set(SQLConfig.operator_AND, "{0} AND {1}");
-        config.set(SQLConfig.operator_OR, "{0} OR {1}");
-        config.set(SQLConfig.operator_EQ, "( ({0}) = ({1}) )");
-        config.set(SQLConfig.operator_NE, "( ({0}) <> ({1}) )");
-        config.set(SQLConfig.operator_GT, "( ({0}) > ({1}) )");
-        config.set(SQLConfig.operator_GE, "( ({0}) >= ({1}) )");
-        config.set(SQLConfig.operator_LT, "( ({0}) < ({1}) )");
-        config.set(SQLConfig.operator_LE, "( ({0}) <= ({1}) )");
-        config.set(SQLConfig.operator_LIKE, "( ({0}) LIKE ({1}) )");
-        config.set(SQLConfig.operator_ILIKE, "( ({0}) ILIKE ({1}) )");
-
-        config.set(SQLConfig.operator_add, "{0} + {1}");
-        config.set(SQLConfig.operator_subst, "{0} - {1}");
-        config.set(SQLConfig.operator_mult, "{0} * {1}");
-        config.set(SQLConfig.operator_div, "{0} / {1}");
-        config.set(SQLConfig.operator_concat, "{0} || {1}");
-
-
-        config.set(SQLConfig.default_schema, "public");
-        config.set(SQLConfig.allowAutomaticValues, true);
-        
-        config.set(SQLConfig.ST_ExtentAggregate, "ST_Extent({0})");
-        config.set(SQLConfig.ST_UnionAggregate, "ST_Union({0})");
-        config.set(SQLConfig.count, "COUNT({0})");
-        config.set(SQLConfig.count_distinct, "COUNT(DISTINCT {0})");
-
-        config.set(SQLConfig.type_boolean, "BOOLEAN");
-        config.set(SQLConfig.type_byte, "TINYINT");
-        config.set(SQLConfig.type_bytearray, "BYTEA");
-        config.set(SQLConfig.type_geometry, "TEXT");
-        config.set(SQLConfig.type_char, "CHARACTER(1)");
-        config.set(SQLConfig.type_date, "DATE");
-        config.set(SQLConfig.type_double, "DOUBLE PRECISION"); //float con 53 bits de mantisa, float(54)
-        config.set(SQLConfig.type_numeric_p, "NUMERIC({0})");
-        config.set(SQLConfig.type_numeric_ps, "NUMERIC({0},{1})");
-        config.set(SQLConfig.type_bigdecimal, "NUMERIC({0},{1})");
-        config.set(SQLConfig.type_float, "REAL"); //float con 24 bits de mantisa, float(24)
-        config.set(SQLConfig.type_int, "INT");
-        config.set(SQLConfig.type_long, "BIGINT");
-        config.set(SQLConfig.type_string, "TEXT");
-        config.set(SQLConfig.type_string_p, "VARCHAR({0})");
-        config.set(SQLConfig.type_time, "TIME");
-        config.set(SQLConfig.type_timestamp, "TIMESTAMP");
-        config.set(SQLConfig.type_version, "VARCHAR(30)");
-        config.set(SQLConfig.type_URI, "TEXT");
-        config.set(SQLConfig.type_URL, "TEXT");
-        config.set(SQLConfig.type_FILE, "TEXT");
-        config.set(SQLConfig.type_FOLDER, "TEXT");
-
-        config.set(SQLConfig.DELETE_FROM_table_WHERE_expresion, "DELETE FROM {0} WHERE {1}");
-        config.set(SQLConfig.DELETE_FROM_table, "DELETE FROM {0}");
-        config.set(SQLConfig.INSERT_INTO_table_columns_VALUES_values, "INSERT INTO {0} ( {1} ) VALUES ( {2} )");
-        config.set(SQLConfig.UPDATE_TABLE_STATISTICS_table, "VACUUM ANALYZE {0}");
-        config.set(SQLConfig.DROP_TABLE_table, "DROP TABLE {0}");
-        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_schema_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_schema = {0} AND f_table_name = {1}");
-        config.set(SQLConfig.DELETE_GEOMETRY_COLUMN_FROM_TABLE_table, "DELETE FROM GEOMETRY_COLUMNS WHERE f_table_name = {0}");
-        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues_WHERE_expresion, "UPDATE {0} SET {1} WHERE {2}");
-        config.set(SQLConfig.UPDATE_table_SET_columnsAndValues, "UPDATE {0} SET {1}");
-        config.set(SQLConfig.GRANT_privileges_ON_table_TO_role, "GRANT {0} ON {1} TO {2}");        
     }
-   
+    
     @Override
-    public ExpressionBuilder createExpressionBuilder() {
-        return ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
+    public void setProperties(Class filter, final Object... values) {
+        this.accept(new Visitor() {
+            @Override
+            public void visit(Visitable v) {
+                for (int i = 0; i < values.length; i+=2) {
+                    ((Value)v).setProperty((String) values[i], values[i+1]);
+                }
+            }
+        }, new ClassVisitorFilter(filter) );
     }
 
-    @Override
-    public Config getConfig() {
-        return this.config;
+    public String quote_for_identifiers() {
+        return "\"";
     }
 
-    @Override
-    public Value getValue() {
-        return this.value;
+    public String quote_for_strings() {
+        return "'";
     }
 
     @Override
-    public ExpressionBuilder setValue(Value value) {
-        this.value = value;
-        return this;
-    }
+    public String as_identifier(String id) {
+        String quote = this.quote_for_identifiers();
+//        No se porque no esta disponible wrapIfMissing
+//        return StringUtils.wrapIfMissing(id,quote);
+        if (id.startsWith(quote)) {
+            return id;
+        }
+        return quote + id + quote;
 
-    @Override
-    public boolean has_spatial_functions() {
-        return this.config.getBoolean(Config.has_spatial_functions);
     }
 
     @Override
-    public GeometrySupportType geometry_support_type() {
-        return (GeometrySupportType) this.config.get(Config.geometry_type_support);
-    }
-
-    @Override
-    public String string(String s) {
-        String quote = this.config.getString(Config.quote_for_strings);
+    public String as_string(String s) {
+        String quote = this.quote_for_strings();
 //        No se porque no esta disponible wrapIfMissing
-//        return StringUtils.wrapIfMissing(s,quote);
+//        return StringUtils.wrapIfMissing(id,quote);
         if (s.startsWith(quote)) {
             return s;
         }
         return quote + s + quote;
-    }
 
-    @Override
-    public String identifier(String id) {
-        String quote = this.config.getString(Config.quote_for_identifiers);
-//        No se porque no esta disponible wrapIfMissing
-//        return StringUtils.wrapIfMissing(id,quote);
-        if (id.startsWith(quote)) {
-            return id;
-        }
-        return quote + id + quote;
     }
 
     @Override
-    public String bytearray(byte[] data) {
-        return bytearray_0x(data);
+    public String as_string(byte[] data) {
+        return this.expressionBuilder.bytearray_0x(data);
+//        return this.expressionBuilder.bytearray_hex(data);
+//        return this.expressionBuilder.bytearray_x(data);
     }
     
-    public String bytearray_hex(byte[] data) {
-        StringBuilder builder = new StringBuilder();
-        for (byte abyte : data) {
-            int v = abyte & 0xff;
-            builder.append(String.format("%02x", v));
-        }
-        return builder.toString();
-    }
-
-    public String bytearray_0x(byte[] data) {
-        return "0x" + bytearray_hex(data);
-    }
-
-    public String bytearray_x(byte[] data) {
-        return "x'" + bytearray_hex(data) + "'";
-    }
-    
     @Override
-    public Object getSRSId(IProjection projection) {
-        String abrev = projection.getAbrev();
-        return abrev.split(":")[1].trim();
+    public String as_string(boolean value) {
+        return value? "TRUE" : "FALSE";
     }
 
     @Override
-    public Constant srs(IProjection projection) {
-        return constant(getSRSId(projection));
+    public String as_string(Number value) {
+        return Objects.toString(value);
     }
-
-    @Override
-    public Variable variable(String name) {
-        return new VariableBase(name);
-    }
-
-    @Override
-    public Column column(String name) {
-        return new VariableBase(name);
-    }
     
     @Override
-    public Parameter parameter(String name) {
-        Parameters parameters = this.getParameters();
-        Parameter parameter = parameters.get(name);
-        if( parameter != null ) {
-            return parameter;
+    public String as_string(Object value) {
+        if( value == null ) {
+            return "NULL";
         }
-        parameter = this.parameter();
-        parameter.name(name);
-        return parameter;
-    }
-    
-    @Override
-    public Parameter parameter() {
-        return new ParameterBase();
-    }
-    
-    @Override
-    public Constant constant(Object value) {
-        return new ConstantBase(value);
-    }
-
-    @Override
-    public Group group(Value value) {
-        return new GroupBase(value);
-    }
-
-    @Override
-    public GeometryValue geometry(Geometry geom, IProjection projection) {
-        return new GeometryValueBase(geom, projection);
-    }
-
-    @Override
-    public GeometryValue geometry(Geometry geom) {
-        if( geom.getProjection()==null ) {
-            throw new IllegalArgumentException("The geometry does not have an associated projection. Use 'geometry(Geometry, IProjection)'.");
+        if( value instanceof CharSequence ) {
+            return as_string(value.toString());
         }
-        return new GeometryValueBase(geom, geom.getProjection());
-    }
-
-    @Override
-    public GeometryValue envelope(Envelope envelope, IProjection projection) {
-        return new GeometryValueBase(envelope.getGeometry(), projection);
-    }
-
-    @Override
-    public GeometryValue envelope(Envelope envelope) {
-        if( envelope.getProjection()==null ) {
-            throw new IllegalArgumentException("The envelope does not have an associated projection. Use 'envelope(Geometry, IProjection)'.");
+        if( value instanceof Number ) {
+            return as_string((Number)value);
         }
-        return new GeometryValueBase(envelope.getGeometry(), envelope.getProjection());
-    }
-
-    @Override
-    public Custom custom(Object value) {
-        return new CustomBase(value);
-    }
-
-    public Function builtin_function(String name, String format, Value... values) {
-        FunctionBase func = new FunctionBase(name, format);
-        for (Value value : values) {
-            func.parameter(value);
+        if( value instanceof Boolean ) {
+            return as_string((boolean)value);
         }
-        return func;
-    }
-
-    public Function function(String name, Value... values) {
-        FunctionBase func = new FunctionBase(name);
-        for (Value theValue : values) {
-            func.parameter(theValue);
+        if( value instanceof byte[] ) {
+            return as_string((byte[])value);
         }
-        return func;
-    }    
-    
-    public BinaryOperator binaryOperator(String name, String format, Value leftOperand, Value rightOperand) {
-        BinaryOperator operator = new BinaryOperatorBase(name, format);
-        operator.setLeft(leftOperand);
-        operator.setRight(rightOperand);
-        return operator;
+        throw new IllegalArgumentException("Can't support type of value '"+value.getClass().getName()+"'.");
     }
-
+    
     @Override
-    public List<Variable> getVariables() {
-        final Set<Variable> vars = new HashSet<>();
-        this.accept(new Visitor() {
-            @Override
-            public void visit(Visitable value) {
-                vars.add((Variable) value);
-            }
-        }, new ClassVisitorFilter(Variable.class));
-        List<Variable> lvars = new ArrayList<>(vars);
-        Collections.sort(lvars);
-        return lvars;
+    public ExpressionBuilder expression() {
+        return this.expressionBuilder;
     }
 
     @Override
-    public Parameters getParameters() {
-        final Parameters params = new ParametersBase();
-        this.accept(new Visitor() {
-            @Override
-            public void visit(Visitable value) {
-                params.add((Parameter) value);
-            }
-        }, new ClassVisitorFilter(Parameter.class));
-        return params;
+    public boolean has_spatial_functions() {
+        return this.hasSpatialFunctions;
     }
 
     @Override
-    public Function getAsGeometry(Value value) {
-        return builtin_function("ST_AsBinary", config.getString(Config.ST_AsBinary), value);
+    public GeometrySupportType geometry_support_type() {
+        return this.geometrySupportType;
     }
 
-    @Override
-    public ExpressionBuilder set(Value value) {
-        this.value = value;
-        return this;
+    protected ExpressionBuilder createExpressionBuilder() {
+        return ExpressionEvaluatorLocator.getManager().createExpressionBuilder();
     }
 
     @Override
-    public ExpressionBuilder and(Value value) {
-        if (this.value == null) {
-            return this.set(value);
-        }
-        BinaryOperator operator = binaryOperator("AND", config.getString(Config.operator_AND), this.value, value);
-        this.value = operator;
-        return this;
+    public Object srs_id(IProjection projection) {
+        String abrev = projection.getAbrev();
+        return abrev.split(":")[1].trim();
     }
 
     @Override
-    public ExpressionBuilder or(Value value) {
-        if (this.value == null) {
-            return this.set(value);
-        }
-        BinaryOperator operator = binaryOperator("OR", config.getString(Config.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);
-    }
-
-    @Override
-    public Function ST_SRID(Value geom) {
-        return builtin_function("ST_SRID", config.getString(Config.ST_SRID), geom);
-    }
-
-    @Override
-    public Function ST_Envelope(Value geom) {
-        return builtin_function("ST_Envelope", config.getString(Config.ST_Envelope), geom);
-    }
-
-    @Override
-    public Function ST_AsText(Value geom) {
-        return builtin_function("ST_AsText", config.getString(Config.ST_AsText), geom);
-    }
-
-    @Override
-    public Function ST_AsBinary(Value geom) {
-        return builtin_function("ST_AsBinary", config.getString(Config.ST_AsBinary), geom);
-    }
-
-    @Override
-    public Function ST_AsEWKB(Value geom) {
-        return builtin_function("ST_AsEWKB", config.getString(Config.ST_AsEWKB), geom);
-    }
-
-    @Override
-    public Function ST_GeomFromText(Value geom, Value crs) {
-        return builtin_function("ST_GeomFromText", config.getString(Config.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);
-    }
-
-    @Override
-    public Function ST_GeomFromEWKB(Value geom, Value crs) {
-        return builtin_function("ST_GeomFromEWKB", config.getString(Config.ST_GeomFromEWKB), geom, crs);
-    }
-
-    @Override
-    public Function ST_Simplify(Value geom, Value tolerance) {
-        return builtin_function("ST_Simplify", config.getString(Config.ST_Simplify), tolerance);
-    }
-
-    @Override
-    public Function ST_Disjoint(Value geom1, Value geom2) {
-        return builtin_function("ST_Disjoint", config.getString(Config.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);
-    }
-
-    @Override
-    public Function ST_Equals(Value geom1, Value geom2) {
-        return builtin_function("ST_Equals", config.getString(Config.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);
-    }
-
-    @Override
-    public Function ST_IsClosed(Value geom) {
-        return builtin_function("ST_IsClosed", config.getString(Config.ST_IsClosed), geom);
-    }
-
-    @Override
-    public Function ST_Overlaps(Value geom1, Value geom2) {
-        return builtin_function("ST_Overlaps", config.getString(Config.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);
-    }
-
-    @Override
-    public Function ST_Within(Value geom1, Value geom2) {
-        return builtin_function("ST_Within", config.getString(Config.ST_Within), geom1, geom2);
-    }
-
-    @Override
-    public Function isNull(Value value) {
-        return builtin_function("IS NULL", config.getString(Config.isNull), value);
-    }
-
-    @Override
-    public Function notIsNull(Value value) {
-        return builtin_function("NOT IS NULL", config.getString(Config.notIsNull), value);
-    }
-
-    @Override
-    public Function not(Value value) {
-        return builtin_function("NOT", config.getString(Config.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);
-    }
-
-    @Override
-    public BinaryOperator or(Value leftOperand, Value rightOperand) {
-        return binaryOperator("OR", config.getString(Config.operator_OR), leftOperand, rightOperand);
-    }
-
-    @Override
-    public BinaryOperator eq(Value leftOperand, Value rightOperand) {
-        return binaryOperator("=", config.getString(Config.operator_EQ), leftOperand, rightOperand);
-    }
-
-    @Override
-    public BinaryOperator ne(Value leftOperand, Value rightOperand) {
-        return binaryOperator("<>", config.getString(Config.operator_NE), leftOperand, rightOperand);
-    }
-
-    @Override
-    public BinaryOperator gt(Value op1, Value op2) {
-        return binaryOperator(">", config.getString(Config.operator_GT), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator ge(Value op1, Value op2) {
-        return binaryOperator(">=", config.getString(Config.operator_GE), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator lt(Value op1, Value op2) {
-        return binaryOperator("<", config.getString(Config.operator_LT), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator le(Value op1, Value op2) {
-        return binaryOperator("<=", config.getString(Config.operator_LE), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator like(Value op1, Value op2) {
-        return binaryOperator("LIKE", config.getString(Config.operator_LIKE), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator ilike(Value op1, Value op2) {
-        return binaryOperator("ILIKE", config.getString(Config.operator_ILIKE), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator add(Value op1, Value op2) {
-        return binaryOperator("ADD", config.getString(Config.operator_add), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator subst(Value op1, Value op2) {
-        return binaryOperator("SUBST", config.getString(Config.operator_subst), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator mult(Value op1, Value op2) {
-        return binaryOperator("MULT", config.getString(Config.operator_mult), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator div(Value op1, Value op2) {
-        return binaryOperator("DIV", config.getString(Config.operator_div), op1, op2);
-    }
-
-    @Override
-    public BinaryOperator concat(Value op1, Value op2) {
-        return binaryOperator("CONCAT", config.getString(Config.operator_concat), op1, op2);
-    }
- 
-    @Override
     public String default_schema() {
-        return config.getString(SQLConfig.default_schema);
+        return this.defaultSchema;
     }
 
     @Override
-    public boolean supportSchemas() {
-        return config.getBoolean(Config.support_schemas);
+    public boolean support_schemas() {
+        return this.supportSchemas;
     }
-    
-    @Override
-    @Deprecated
-    public String sqltype(int type, int p, int s) {
-        return this.sqltype(type, p, s, Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.UNKNOWN);
-    }
 
     @Override
     public String sqltype(int type, int p, int s, int geomType, int geomSubtype) {
         switch (type) {
             case DataTypes.BOOLEAN:
-                return config.getString(SQLConfig.type_boolean);
+                return type_boolean;
             case DataTypes.BYTE:
-                return config.getString(SQLConfig.type_byte);
+                return type_byte;
             case DataTypes.BYTEARRAY:
-                return config.getString(SQLConfig.type_bytearray);
+                return type_bytearray;
             case DataTypes.GEOMETRY:
-                return config.getString(SQLConfig.type_geometry);
+                return type_geometry;
             case DataTypes.CHAR:
-                return config.getString(SQLConfig.type_char);
+                return type_char;
             case DataTypes.DATE:
-                return config.getString(SQLConfig.type_date);
+                return type_date;
             case DataTypes.DOUBLE:
-                  // FIXME: Si cargamos la capa "country" al exportarla a
-                  // SQLServer falla por:
-                  //  Error de desbordamiento aritmético al convertir float al tipo de datos numeric.
-                  // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
-                  // Algeria intenta asignarle un valor de 2320972.0 y falla.
-                  // Habria que repasar el proveedor de shape.
-                
+                // FIXME: Si cargamos la capa "country" al exportarla a
+                // SQLServer falla por:
+                //  Error de desbordamiento aritmético al convertir float al tipo de datos numeric.
+                // Al parecer la capa declara la columna sqkm_ctry como Numeric(12,6) y para 
+                // Algeria intenta asignarle un valor de 2320972.0 y falla.
+                // Habria que repasar el proveedor de shape.
+
 //                if (p > 1) {
 //                    if (s < 0) {
 //                        return MessageFormat.format(config.getString(SQLConfig.type_numeric_p), p);
 //                    }
 //                    return MessageFormat.format(config.getString(SQLConfig.type_numeric_ps), p,s);
 //                }
-                return MessageFormat.format(config.getString(SQLConfig.type_double),p,s);
+                return MessageFormat.format(type_double, p, s);
             case DataTypes.BIGDECIMAL:
                 if (p < 1) {
                     p = 20;
@@ -3183,94 +2446,92 @@
                 if (s < 0) {
                     s = 10;
                 }
-                return MessageFormat.format(config.getString(SQLConfig.type_bigdecimal), p,s);
+                return MessageFormat.format(type_bigdecimal, p, s);
             case DataTypes.FLOAT:
-                return MessageFormat.format(config.getString(SQLConfig.type_float), p,s);
+                return MessageFormat.format(type_float, p, s);
             case DataTypes.INT:
-                return MessageFormat.format(config.getString(SQLConfig.type_int), p,s);
+                return MessageFormat.format(type_int, p, s);
             case DataTypes.LONG:
-                return MessageFormat.format(config.getString(SQLConfig.type_long), p,s);
+                return MessageFormat.format(type_long, p, s);
             case DataTypes.STRING:
                 if (p < 0) {
-                    return config.getString(SQLConfig.type_string);
+                    return type_string;
                 } else if (p < 4096) {
-                    return MessageFormat.format(config.getString(SQLConfig.type_string_p),p);
+                    return MessageFormat.format(type_string_p, p);
                 }
-                return config.getString(SQLConfig.type_string);
+                return type_string;
             case DataTypes.TIME:
-                return config.getString(SQLConfig.type_time);
+                return type_time;
             case DataTypes.TIMESTAMP:
-                return config.getString(SQLConfig.type_timestamp);
+                return type_timestamp;
             case DataTypes.VERSION:
-                return config.getString(SQLConfig.type_version);
+                return type_version;
             case DataTypes.URI:
-                return config.getString(SQLConfig.type_URI);
+                return type_URI;
             case DataTypes.URL:
-                return config.getString(SQLConfig.type_URL);
+                return type_URL;
             case DataTypes.FILE:
-                return config.getString(SQLConfig.type_FILE);
+                return type_FILE;
             case DataTypes.FOLDER:
-                return config.getString(SQLConfig.type_FOLDER);
+                return type_FOLDER;
             default:
                 return null;
         }
     }
 
-    private static Map<Pair<Integer,Integer>,String> sqlgeometrytypes = null;
-    
     @Override
     public Object sqlgeometrytype(int type, int subtype) {
         // Devuelve un Object por que algunos gestores de BBDD utilizan
         // identificadores numericos para el tipo y otros strings.
         // Por defecto vamos a devolver strings.
-        if( sqlgeometrytypes==null ) {
+        if (sqlgeometrytypes == null) {
             sqlgeometrytypes = new HashMap<>();
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2D), "POINT");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3D), "POINTZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM2DM), "POINTM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POINT,Geometry.SUBTYPES.GEOM3DM), "POINTZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2D), "POINT");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3D), "POINTZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM2DM), "POINTM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POINT, Geometry.SUBTYPES.GEOM3DM), "POINTZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2D), "LINESTRING");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.LINE,Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2D), "LINESTRING");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3D), "LINESTRINGZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM2DM), "LINESTRINGM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.LINE, Geometry.SUBTYPES.GEOM3DM), "LINESTRINGZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2D), "POLYGON");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.POLYGON,Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2D), "POLYGON");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3D), "POLYGONZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM2DM), "POLYGONM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.POLYGON, Geometry.SUBTYPES.GEOM3DM), "POLYGONZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOINT,Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2D), "MULTIPOINT");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3D), "MULTIPOINTZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM2DM), "MULTIPOINTM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOINT, Geometry.SUBTYPES.GEOM3DM), "MULTIPOINTZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTILINE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTILINE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTICURVE,Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2D), "MULTILINESTRING");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3D), "MULTILINESTRINGZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM2DM), "MULTILINESTRINGM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTICURVE, Geometry.SUBTYPES.GEOM3DM), "MULTILINESTRINGZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTIPOLYGON, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.MULTISURFACE,Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2D), "MULTIPOLYGON");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3D), "MULTIPOLYGONZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM2DM), "MULTIPOLYGONM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.MULTISURFACE, Geometry.SUBTYPES.GEOM3DM), "MULTIPOLYGONZM");
 
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
-            sqlgeometrytypes.put( new ImmutablePair<>(Geometry.TYPES.GEOMETRY,Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2D), "GEOMETRY");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3D), "GEOMETRYZ");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM2DM), "GEOMETRYM");
+            sqlgeometrytypes.put(new ImmutablePair<>(Geometry.TYPES.GEOMETRY, Geometry.SUBTYPES.GEOM3DM), "GEOMETRYZM");
         }
-        return sqlgeometrytypes.get(new ImmutablePair<>(type,subtype));
+        return sqlgeometrytypes.get(new ImmutablePair<>(type, subtype));
     }
 
     @Override
@@ -3278,7 +2539,7 @@
         // Devuelve un Object por que algunos gestortes de BBDD utilizan
         // identificadores numericos para las dimensiones y otros strings.
         // Por defecto vamos a devolver enteros.
-        switch(subtype) {
+        switch (subtype) {
             case Geometry.SUBTYPES.GEOM3D:
                 return 3;
             case Geometry.SUBTYPES.GEOM2DM:
@@ -3290,23 +2551,23 @@
                 return 2;
         }
     }
-    
+
     protected TableNameBuilder createTableNameBuilder() {
         return new TableNameBuilderBase();
     }
-    
+
     protected SelectColumnBuilder createSelectColumnBuilder() {
         return new SelectColumnBuilderBase();
     }
-    
+
     protected UpdateColumnBuilder createUpdateColumnBuilder() {
         return new UpdateColumnBuilderBase();
     }
-    
+
     protected InsertColumnBuilder createInsertColumnBuilder() {
         return new InsertColumnBuilderBase();
     }
-    
+
     protected OrderByBuilder createOrderByBuilder() {
         return new OrderByBuilderBase();
     }
@@ -3334,7 +2595,7 @@
     protected GrantRoleBuilder createGrantRoleBuilder(TableNameBuilder table, String role) {
         return new GrantRoleBuilderBase(table, role);
     }
-    
+
     protected DropTableBuilder createDropTableBuilder() {
         return new DropTableBuilderBase();
     }
@@ -3358,7 +2619,7 @@
     protected CreateIndexBuilder createCreateIndexBuilder() {
         return new CreateIndexBuilderBase();
     }
-    
+
     @Override
     public SelectBuilder select() {
         if (this.select == null) {
@@ -3399,7 +2660,6 @@
         return this.create_index;
     }
 
-    
     @Override
     public DeleteBuilder delete() {
         if (this.delete == null) {
@@ -3440,7 +2700,6 @@
         return this.grant;
     }
 
-    @Override
     public void accept(Visitor visitor, VisitorFilter filter) {
         if (this.select != null) {
             this.select.accept(visitor, filter);
@@ -3463,334 +2722,110 @@
         if (this.drop_table != null) {
             this.drop_table.accept(visitor, filter);
         }
-//        if( this.value == null) {
-//            return;
-//        }
-//        this.value.accept(visitor, filter);
     }
 
-    
+    protected Formatter formatter() {
+        return ExpressionBuilder.EMPTY_FORMATTER;
+    }
+
     @Override
     public String toString() {
+        return this.toString(formatter());
+    }
+
+    @Override
+    public String toString(Formatter formatter) {
         if (this.select != null) {
-            return this.select.toString();
+            return this.select.toString(formatter);
         }
         if (this.update != null) {
-            return this.update.toString();
+            return this.update.toString(formatter);
         }
         if (this.insert != null) {
-            return this.insert.toString();
+            return this.insert.toString(formatter);
         }
         if (this.delete != null) {
-            return this.delete.toString();
+            return this.delete.toString(formatter);
         }
         if (this.alter_table != null) {
-            return this.alter_table.toString();
+            return this.alter_table.toString(formatter);
         }
         if (this.create_table != null) {
-            return this.create_table.toString();
+            return this.create_table.toString(formatter);
         }
         if (this.drop_table != null) {
-            return this.drop_table.toString();
+            return this.drop_table.toString(formatter);
         }
         if (this.update_table_statistics != null) {
-            return this.update_table_statistics.toString();
+            return this.update_table_statistics.toString(formatter);
         }
-        if ( this.value != null ) {
-            return this.value.toString();
-        }
-        return ""; 
+        return "";
     }
 
     @Override
-    public Function ST_UnionAggregate(Value geom) {
-        return builtin_function("ST_UnionAggregate", config.getString(SQLConfig.ST_UnionAggregate), geom);
+    public CountBuilder count() {
+        return new CountBuilderBase();
     }
 
     @Override
-    public Function ST_ExtentAggregate(Value geom) {
-        return builtin_function("ST_ExtentAggregate", config.getString(SQLConfig.ST_ExtentAggregate), geom);
+    public List<Parameter> parameters() {
+        final List<Parameter> params = new ArrayList<>();
+        this.accept(new Visitor() {
+            @Override
+            public void visit(Visitable value) {
+                params.add((Parameter) value);
+            }
+        }, new ClassVisitorFilter(Parameter.class));
+        return params;
     }
 
     @Override
-    public CountBuilder count() {
-        return new CountBuilderBase();
+    public List<Variable> variables() {
+        final List<Variable> vars = new ArrayList<>();
+        this.accept(new Visitor() {
+            @Override
+            public void visit(Visitable value) {
+                if (!vars.contains((Variable) value)) {
+                    vars.add((Variable) value);
+                }
+            }
+        }, new ClassVisitorFilter(Variable.class));
+        return vars;
     }
 
     @Override
-    public Column column(FeatureAttributeDescriptor fad) {
-        ColumnDescriptorBase descriptor;
-        if( fad.getType()==org.gvsig.fmap.geom.DataTypes.GEOMETRY ) {
-            descriptor = new ColumnDescriptorBase(
-                    fad.getName(),
-                    fad.getGeomType().getType(),
-                    fad.getGeomType().getSubType(),
-                    fad.getSRS(),
-                    fad.isIndexed(),
-                    fad.allowNull()
-            );
-        } else {
-            descriptor = new ColumnDescriptorBase(
-                    fad.getName(),
-                    fad.getType(),
-                    fad.getSize(),
-                    fad.getPrecision(),
-                    fad.isPrimaryKey(),
-                    fad.isIndexed(),
-                    fad.allowNull(),
-                    fad.isAutomatic(),
-                    fad.getDefaultValue()
-            );
+    public List<String> parameters_names() {
+        List<String> params = new ArrayList<>();
+        for (Parameter param : parameters()) {
+            String s;
+            switch (param.type()) {
+                case Constant:
+                    Object theValue = param.value();
+                    if (theValue == null) {
+                        s = "null";
+                    } else if (theValue instanceof String) {
+                        s = "'" + (String) theValue + "'";
+                    } else {
+                        s = theValue.toString();
+                    }
+                    break;
+                case Geometry:
+                case Variable:
+                default:
+                    s = "\"" + param.name() + "\"";
+            }
+            params.add(s);
         }
-        FeatureStore store = fad.getStore();
-        if( store!=null ) {
-            descriptor.setStoreParameters(store.getParameters());
-        }
-        return new VariableBase(descriptor);
+        return params;
     }
-    
-    @Override
-    public Function Find_SRID(Value schema, Value table, Value column) {
-        return builtin_function("Find_SRID", config.getString(SQLConfig.Find_SRID), schema, table, column);
-    }
 
-
-    public Function iif(Value condition, Value iftrue, Value iffalse) {
-        return builtin_function("IIF", config.getString(Config.iif), condition, iftrue, iffalse);
-    }
-
-    public Function ifnull(Value value, Value iftrue, Value iffalse) {
-        return builtin_function("IFNULL", config.getString(Config.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);
+    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 right(Value str, Value len) {
-       return function("right", str, len);
-    }
-    
-    @Override
-    public Function locate(Value search, Value str, Value start) {
-       return function("locate", search, str, start);
-    }
-    
-    @Override
-    public Function position(Value search, Value str) {
-       return function("position", search, str);
-    }
-    
-    @Override
-    public Function lpad(Value str, Value len, Value padstr) {
-       return function("lpad", str, len, padstr);
-    }
-    
-    @Override
-    public Function rpad(Value str, Value len, Value padstr) {
-       return function("rpad", str, len, padstr);
-    }
-    
-    @Override
-    public Function ltrim(Value str) {
-       return function("ltrim", str);
-    }
-    
-    @Override
-    public Function rtrim(Value str) {
-       return function("rtrim", str);
-    }
-    
-    @Override
-    public Function trim(Value str) {
-       return function("trim", str);
-    }
-    
-    @Override
-    public Function repeat(Value str, Value size) {
-       return function("repeat", str, size);
-    }
-    
-    @Override
-    public Function replace(Value str, Value search, Value replstr) {
-       return function("replace", str, search, replstr);
-    }
-    
-    @Override
-    public Function ascii(Value str) {
-       return function("ascii", str);
-    }
-    
-    @Override
-    public Function lenght(Value str) {
-       return function("lenght", str);
-    }
-
-    @Override
-    public Function instr(Value str, Value search, Value start) {
-       return function("instr", str, search, start);
-    }
-    
-    @Override
-    public Function lower(Value str) {
-       return function("lower", str);
-    }
-    
-    @Override
-    public Function upper(Value str) {
-       return function("upper", str);
-    }
-    
-    @Override
-    public Function space(Value size) {
-       return function("space", size);
-    }
-    
-    @Override
-    public Function substring(Value str, Value start, Value len) {
-       return function("substring", str, start, len);
-    }
-    
-    @Override
-    public Function acos(Value num) {
-       return function("acos", num);
-    } 
-    
-    @Override
-    public Function asin(Value num) {
-       return function("asin", num);
-    }
-    
-    @Override
-    public Function atan(Value num) {
-       return function("atan", num);
-    }
-    
-    @Override
-    public Function cos(Value num) {
-       return function("cos", num);
-    }
-    
-    @Override
-    public Function cosh(Value num) {
-       return function("cosh", num);
-    }
-    
-    @Override
-    public Function cot(Value num) {
-       return function("cot", num);
-    }  
-    
-    @Override
-    public Function bitand(Value num1, Value num2) {
-       return function("bitand", num1, num2);
-    } 
-    
-    @Override
-    public Function bitor(Value num1, Value num2) {
-       return function("bitor", num1, num2);
-    }
-    
-    @Override
-    public Function bitxor(Value num1, Value num2) {
-       return function("bitxor", num1, num2);
-    }
-    
-    @Override
-    public Function ceil(Value num) {
-       return function("ceil", num);
-    }
-    
-    @Override
-    public Function degrees(Value num) {
-       return function("degrees", num);
-    }  
-    
-    @Override
-    public Function exp(Value num) {
-       return function("exp", num);
-    }  
-    
-    @Override
-    public Function floor(Value num) {
-       return function("floor", num);
-    }  
-    
-    @Override
-    public Function log(Value num) {
-       return function("log", num);
-    }  
-    
-    @Override
-    public Function log10(Value num) {
-       return function("log10", num);
-    }  
-    
-    @Override
-    public Function pi(Value num) {
-       return function("pi", num);
-    }
-    
-    @Override
-    public Function power(Value num) {
-       return function("power", num);
-    }
-    
-    @Override
-    public Function radians(Value num) {
-       return function("radians", num);
-    }
-    
-    @Override
-    public Function rand(Value num) {
-       return function("rand", num);
-    }
-    
-    @Override
-    public Function round(Value num) {
-       return function("round", num);
-    }
-    
-    @Override
-    public Function sqrt(Value num) {
-       return function("sqrt", num);
-    }
-    
-    @Override
-    public Function sign(Value num) {
-       return function("sign", num);
-    }
-    
-    @Override
-    public Function sin(Value num) {
-       return function("sin", num);
-    }
-    
-    @Override
-    public Function sinh(Value num) {
-       return function("sinh", num);
-    }
-    
-    @Override
-    public Function tan(Value num) {
-       return function("tan", num);
-    }
-    @Override
-    public Function tanh(Value num) {
-       return function("cosh", num);
-    }  
-    
-    @Override
-    public Function zero() {
-       return function("zero");
-    }
-    
-    @Override
-    public Function chr(Value num) {
-       return function("chr", num);
-    }
 }
