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 BLOB = new ColumnType(ColumnSpec.BLOB);
059
060    public static final ColumnType ARRAY_STRING = new ColumnType(ColumnSpec.ARRAY_STRING, -1, true);
061
062    public static final ColumnType ARRAY_CLOB = new ColumnType(ColumnSpec.ARRAY_STRING, CLOB_LENGTH, true);
063
064    public static final ColumnType ARRAY_BOOLEAN = new ColumnType(ColumnSpec.ARRAY_BOOLEAN, -1, true);
065
066    public static final ColumnType ARRAY_LONG = new ColumnType(ColumnSpec.ARRAY_LONG, -1, true);
067
068    public static final ColumnType ARRAY_DOUBLE = new ColumnType(ColumnSpec.ARRAY_DOUBLE, -1, true);
069
070    public static final ColumnType ARRAY_TIMESTAMP = new ColumnType(ColumnSpec.ARRAY_TIMESTAMP, -1, true);
071
072    public static final ColumnType ARRAY_BLOBID = new ColumnType(ColumnSpec.ARRAY_BLOBID, -1, true);
073
074    public static final ColumnType ARRAY_INTEGER = new ColumnType(ColumnSpec.ARRAY_INTEGER, -1, true);
075
076    public static final ColumnType NODEID = new ColumnType(ColumnSpec.NODEID);
077
078    public static final ColumnType NODEIDFK = new ColumnType(ColumnSpec.NODEIDFK);
079
080    public static final ColumnType NODEIDFKNP = new ColumnType(ColumnSpec.NODEIDFKNP);
081
082    public static final ColumnType NODEIDFKMUL = new ColumnType(ColumnSpec.NODEIDFKMUL);
083
084    public static final ColumnType NODEIDFKNULL = new ColumnType(ColumnSpec.NODEIDFKNULL);
085
086    public static final ColumnType NODEIDPK = new ColumnType(ColumnSpec.NODEIDPK);
087
088    public static final ColumnType NODEVAL = new ColumnType(ColumnSpec.NODEVAL);
089
090    public static final ColumnType NODEARRAY = new ColumnType(ColumnSpec.NODEARRAY, -1, true);
091
092    public static final ColumnType SYSNAME = new ColumnType(ColumnSpec.SYSNAME);
093
094    public static final ColumnType SYSNAMEARRAY = new ColumnType(ColumnSpec.SYSNAMEARRAY, -1, true);
095
096    public static final ColumnType TINYINT = new ColumnType(ColumnSpec.TINYINT);
097
098    public static final ColumnType INTEGER = new ColumnType(ColumnSpec.INTEGER);
099
100    public static final ColumnType AUTOINC = new ColumnType(ColumnSpec.AUTOINC);
101
102    public static final ColumnType FTINDEXED = new ColumnType(ColumnSpec.FTINDEXED);
103
104    public static final ColumnType FTSTORED = new ColumnType(ColumnSpec.FTSTORED);
105
106    public static final ColumnType CLUSTERNODE = new ColumnType(ColumnSpec.CLUSTERNODE);
107
108    public static final ColumnType CLUSTERFRAGS = new ColumnType(ColumnSpec.CLUSTERFRAGS);
109
110    public final ColumnSpec spec;
111
112    public final int length;
113
114    public final boolean array;
115
116    public ColumnType(ColumnSpec spec, int length, boolean array) {
117        this.spec = spec;
118        this.length = length;
119        this.array = array;
120    }
121
122    public ColumnType(ColumnSpec spec, int length) {
123        this(spec, length, false);
124    }
125
126    public ColumnType(ColumnSpec spec) {
127        this(spec, -1);
128    }
129
130    public boolean isUnconstrained() {
131        return length == -1;
132    }
133
134    public boolean isClob() {
135        return length == CLOB_LENGTH;
136    }
137
138    public boolean isArray() {
139        return array;
140    }
141
142    /**
143     * Checks if this column holds a Nuxeo unique id (usually UUID).
144     */
145    public boolean isId() {
146        return spec.isId();
147    }
148
149    /**
150     * Wraps a string that needs to be mapped to an id column in prepared statements.
151     *
152     * @since 5.7
153     */
154    public static class WrappedId implements Serializable {
155        private static final long serialVersionUID = 1L;
156
157        public final String string;
158
159        public WrappedId(String string) {
160            this.string = string;
161        }
162
163        @Override
164        public String toString() {
165            return string;
166        }
167    }
168
169    @Override
170    public String toString() {
171        if (isUnconstrained()) {
172            return spec.toString();
173        } else if (isClob()) {
174            return isArray() ? "ARRAY_CLOB" : "CLOB";
175        } else {
176            return spec.toString() + '(' + length + ')';
177        }
178    }
179
180    /**
181     * Gets the column type from a Nuxeo Schema field, including its constrained length if any.
182     */
183    public static ColumnType fromField(Field field) {
184        return fromFieldType(field.getType(), field.getMaxLength());
185    }
186
187    /**
188     * Gets the column type from a Nuxeo Schema field type (unconstrained).
189     */
190    public static ColumnType fromFieldType(Type type) {
191        return fromFieldType(type, -1);
192    }
193
194    /**
195     * Gets the column type from a Nuxeo Schema field type (unconstrained) with array {@code true} if an array type is
196     * required
197     */
198    public static ColumnType fromFieldType(Type type, boolean array) {
199        return fromFieldType(type, -1, array);
200    }
201
202    protected static ColumnType fromFieldType(Type type, int maxLength) {
203        return fromFieldType(type, maxLength, false);
204    }
205
206    protected static ColumnType fromFieldType(Type type, int maxLength, boolean array) {
207        if (type instanceof StringType) {
208            if (maxLength == -1) {
209                return array ? ARRAY_STRING : STRING; // unconstrained
210            } else {
211                return new ColumnType(ColumnSpec.STRING, maxLength, array);
212            }
213        } else if (type instanceof BooleanType) {
214            return array ? ARRAY_BOOLEAN : BOOLEAN;
215        } else if (type instanceof LongType) {
216            return array ? ARRAY_LONG : LONG;
217        } else if (type instanceof DoubleType) {
218            return array ? ARRAY_DOUBLE : DOUBLE;
219        } else if (type instanceof DateType) {
220            return array ? ARRAY_TIMESTAMP : TIMESTAMP;
221        } else if (type instanceof BinaryType) {
222            return array ? ARRAY_BLOBID : BLOBID;
223        } else if (type instanceof IntegerType) {
224            return array ? ARRAY_INTEGER : INTEGER;
225        } else if (type instanceof SimpleTypeImpl) {
226            // comes from a constraint
227            return fromFieldType(type.getSuperType(), maxLength);
228        } else {
229            throw new RuntimeException("Invalid primitive type: " + type.getClass().getName());
230        }
231    }
232
233}