001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Florent Guillaume
018 */
019package org.nuxeo.ecm.core.storage.sql;
020
021import java.io.Serializable;
022
023import org.nuxeo.ecm.core.schema.types.Field;
024import org.nuxeo.ecm.core.schema.types.SimpleTypeImpl;
025import org.nuxeo.ecm.core.schema.types.Type;
026import org.nuxeo.ecm.core.schema.types.primitives.BinaryType;
027import org.nuxeo.ecm.core.schema.types.primitives.BooleanType;
028import org.nuxeo.ecm.core.schema.types.primitives.DateType;
029import org.nuxeo.ecm.core.schema.types.primitives.DoubleType;
030import org.nuxeo.ecm.core.schema.types.primitives.IntegerType;
031import org.nuxeo.ecm.core.schema.types.primitives.LongType;
032import org.nuxeo.ecm.core.schema.types.primitives.StringType;
033
034/**
035 * The database-level column types, including per-type parameters like length.
036 */
037public class ColumnType implements Serializable {
038
039    private static final long serialVersionUID = 1L;
040
041    /** Length used internally to flag a string to use CLOB. */
042    public static final int CLOB_LENGTH = 999999999;
043
044    public static final ColumnType STRING = new ColumnType(ColumnSpec.STRING);
045
046    public static final ColumnType CLOB = new ColumnType(ColumnSpec.STRING, CLOB_LENGTH);
047
048    public static final ColumnType BOOLEAN = new ColumnType(ColumnSpec.BOOLEAN);
049
050    public static final ColumnType LONG = new ColumnType(ColumnSpec.LONG);
051
052    public static final ColumnType DOUBLE = new ColumnType(ColumnSpec.DOUBLE);
053
054    public static final ColumnType TIMESTAMP = new ColumnType(ColumnSpec.TIMESTAMP);
055
056    public static final ColumnType BLOBID = new ColumnType(ColumnSpec.BLOBID);
057
058    public static final ColumnType ARRAY_STRING = new ColumnType(ColumnSpec.ARRAY_STRING, -1, true);
059
060    public static final ColumnType ARRAY_CLOB = new ColumnType(ColumnSpec.ARRAY_STRING, CLOB_LENGTH, true);
061
062    public static final ColumnType ARRAY_BOOLEAN = new ColumnType(ColumnSpec.ARRAY_BOOLEAN, -1, true);
063
064    public static final ColumnType ARRAY_LONG = new ColumnType(ColumnSpec.ARRAY_LONG, -1, true);
065
066    public static final ColumnType ARRAY_DOUBLE = new ColumnType(ColumnSpec.ARRAY_DOUBLE, -1, true);
067
068    public static final ColumnType ARRAY_TIMESTAMP = new ColumnType(ColumnSpec.ARRAY_TIMESTAMP, -1, true);
069
070    public static final ColumnType ARRAY_BLOBID = new ColumnType(ColumnSpec.ARRAY_BLOBID, -1, true);
071
072    public static final ColumnType ARRAY_INTEGER = new ColumnType(ColumnSpec.ARRAY_INTEGER, -1, true);
073
074    public static final ColumnType NODEID = new ColumnType(ColumnSpec.NODEID);
075
076    public static final ColumnType NODEIDFK = new ColumnType(ColumnSpec.NODEIDFK);
077
078    public static final ColumnType NODEIDFKNP = new ColumnType(ColumnSpec.NODEIDFKNP);
079
080    public static final ColumnType NODEIDFKMUL = new ColumnType(ColumnSpec.NODEIDFKMUL);
081
082    public static final ColumnType NODEIDFKNULL = new ColumnType(ColumnSpec.NODEIDFKNULL);
083
084    public static final ColumnType NODEIDPK = new ColumnType(ColumnSpec.NODEIDPK);
085
086    public static final ColumnType NODEVAL = new ColumnType(ColumnSpec.NODEVAL);
087
088    public static final ColumnType NODEARRAY = new ColumnType(ColumnSpec.NODEARRAY, -1, true);
089
090    public static final ColumnType SYSNAME = new ColumnType(ColumnSpec.SYSNAME);
091
092    public static final ColumnType SYSNAMEARRAY = new ColumnType(ColumnSpec.SYSNAMEARRAY, -1, true);
093
094    public static final ColumnType TINYINT = new ColumnType(ColumnSpec.TINYINT);
095
096    public static final ColumnType INTEGER = new ColumnType(ColumnSpec.INTEGER);
097
098    public static final ColumnType AUTOINC = new ColumnType(ColumnSpec.AUTOINC);
099
100    public static final ColumnType FTINDEXED = new ColumnType(ColumnSpec.FTINDEXED);
101
102    public static final ColumnType FTSTORED = new ColumnType(ColumnSpec.FTSTORED);
103
104    public static final ColumnType CLUSTERNODE = new ColumnType(ColumnSpec.CLUSTERNODE);
105
106    public static final ColumnType CLUSTERFRAGS = new ColumnType(ColumnSpec.CLUSTERFRAGS);
107
108    public final ColumnSpec spec;
109
110    public final int length;
111
112    public final boolean array;
113
114    public ColumnType(ColumnSpec spec, int length, boolean array) {
115        this.spec = spec;
116        this.length = length;
117        this.array = array;
118    }
119
120    public ColumnType(ColumnSpec spec, int length) {
121        this(spec, length, false);
122    }
123
124    public ColumnType(ColumnSpec spec) {
125        this(spec, -1);
126    }
127
128    public boolean isUnconstrained() {
129        return length == -1;
130    }
131
132    public boolean isClob() {
133        return length == CLOB_LENGTH;
134    }
135
136    public boolean isArray() {
137        return array;
138    }
139
140    /**
141     * Checks if this column holds a Nuxeo unique id (usually UUID).
142     */
143    public boolean isId() {
144        return spec.isId();
145    }
146
147    /**
148     * Wraps a string that needs to be mapped to an id column in prepared statements.
149     *
150     * @since 5.7
151     */
152    public static class WrappedId implements Serializable {
153        private static final long serialVersionUID = 1L;
154
155        public final String string;
156
157        public WrappedId(String string) {
158            this.string = string;
159        }
160
161        @Override
162        public String toString() {
163            return string;
164        }
165    }
166
167    @Override
168    public String toString() {
169        if (isUnconstrained()) {
170            return spec.toString();
171        } else if (isClob()) {
172            return isArray() ? "ARRAY_CLOB" : "CLOB";
173        } else {
174            return spec.toString() + '(' + length + ')';
175        }
176    }
177
178    /**
179     * Gets the column type from a Nuxeo Schema field, including its constrained length if any.
180     */
181    public static ColumnType fromField(Field field) {
182        return fromFieldType(field.getType(), field.getMaxLength());
183    }
184
185    /**
186     * Gets the column type from a Nuxeo Schema field type (unconstrained).
187     */
188    public static ColumnType fromFieldType(Type type) {
189        return fromFieldType(type, -1);
190    }
191
192    /**
193     * Gets the column type from a Nuxeo Schema field type (unconstrained) with array {@code true} if an array type is
194     * required
195     */
196    public static ColumnType fromFieldType(Type type, boolean array) {
197        return fromFieldType(type, -1, array);
198    }
199
200    protected static ColumnType fromFieldType(Type type, int maxLength) {
201        return fromFieldType(type, maxLength, false);
202    }
203
204    protected static ColumnType fromFieldType(Type type, int maxLength, boolean array) {
205        if (type instanceof StringType) {
206            if (maxLength == -1) {
207                return array ? ARRAY_STRING : STRING; // unconstrained
208            } else {
209                return new ColumnType(ColumnSpec.STRING, maxLength, array);
210            }
211        } else if (type instanceof BooleanType) {
212            return array ? ARRAY_BOOLEAN : BOOLEAN;
213        } else if (type instanceof LongType) {
214            return array ? ARRAY_LONG : LONG;
215        } else if (type instanceof DoubleType) {
216            return array ? ARRAY_DOUBLE : DOUBLE;
217        } else if (type instanceof DateType) {
218            return array ? ARRAY_TIMESTAMP : TIMESTAMP;
219        } else if (type instanceof BinaryType) {
220            return array ? ARRAY_BLOBID : BLOBID;
221        } else if (type instanceof IntegerType) {
222            return array ? ARRAY_INTEGER : INTEGER;
223        } else if (type instanceof SimpleTypeImpl) {
224            // comes from a constraint
225            return fromFieldType(type.getSuperType(), maxLength);
226        } else {
227            throw new RuntimeException("Invalid primitive type: " + type.getClass().getName());
228        }
229    }
230
231}