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