001: /*
002: * ColumnIdentifier.java
003: *
004: * This file is part of SQL Workbench/J, http://www.sql-workbench.net
005: *
006: * Copyright 2002-2008, Thomas Kellerer
007: * No part of this code maybe reused without the permission of the author
008: *
009: * To contact the author please send an email to: support@sql-workbench.net
010: *
011: */
012: package workbench.db;
013:
014: import java.math.BigDecimal;
015: import java.sql.Timestamp;
016: import java.sql.Types;
017: import java.util.Collections;
018: import java.util.Comparator;
019: import java.util.List;
020: import workbench.util.SqlUtil;
021: import workbench.util.StringUtil;
022:
023: /**
024: * An object containing the definition for a table column.
025: * @author support@sql-workbench.net
026: */
027: public class ColumnIdentifier implements DbObject,
028: Comparable<ColumnIdentifier> {
029: private String name;
030: private int type = Types.OTHER;
031: private boolean isPk;
032: private boolean isExpression;
033: private boolean isNullable = true;
034: private boolean isUpdateable = true;
035: private String dbmsType;
036: private String comment;
037: private String defaultValue;
038: private String columnClassName;
039: private Class columnClass;
040: private String columnTypeName;
041:
042: private int position;
043:
044: private int size; // for VARCHAR etc
045: private int digits; // for DECIMAL types
046: private int hashCode;
047:
048: public ColumnIdentifier() {
049: }
050:
051: public ColumnIdentifier(String aName) {
052: this (aName, Types.OTHER, false);
053: }
054:
055: public ColumnIdentifier(String aName, int aType) {
056: this (aName, aType, false);
057: }
058:
059: public ColumnIdentifier(String aName, int aType, boolean isPkColumn) {
060: if (aName == null)
061: throw new IllegalArgumentException(
062: "Column name may not be null!");
063: setColumnName(aName.trim());
064: this .type = aType;
065: this .isPk = isPkColumn;
066: }
067:
068: public String getSchema() {
069: return null;
070: }
071:
072: public String getCatalog() {
073: return null;
074: }
075:
076: public String getObjectName(WbConnection conn) {
077: return conn.getMetadata().quoteObjectname(this .name);
078: }
079:
080: public String getObjectExpression(WbConnection conn) {
081: return getObjectName(conn);
082: }
083:
084: public String getObjectType() {
085: return "COLUMN";
086: }
087:
088: public String getObjectName() {
089: return getColumnName();
090: }
091:
092: public CharSequence getSource(WbConnection con) {
093: return this .name + " " + this .dbmsType;
094: }
095:
096: /**
097: * Define the size for this column (e.g. for VARCHAR columns)
098: */
099: public void setColumnSize(int aSize) {
100: this .size = aSize;
101: }
102:
103: public int getColumnSize() {
104: return this .size;
105: }
106:
107: /**
108: * Define the decimal digits for this column (e.g. for DECIMAL columns)
109: */
110: public void setDecimalDigits(int numDigits) {
111: this .digits = numDigits;
112: }
113:
114: public int getDecimalDigits() {
115: return this .digits;
116: }
117:
118: public void setIsPkColumn(boolean flag) {
119: this .isPk = flag;
120: }
121:
122: public boolean isPkColumn() {
123: return this .isPk;
124: }
125:
126: public void setIsNullable(boolean flag) {
127: this .isNullable = flag;
128: }
129:
130: public boolean isNullable() {
131: return this .isNullable;
132: }
133:
134: public void setDbmsType(String type) {
135: this .dbmsType = type;
136: }
137:
138: public String getDbmsType() {
139: return this .dbmsType;
140: }
141:
142: public boolean isIdentityColumn() {
143: if (this .dbmsType == null)
144: return false;
145: return (dbmsType.indexOf("identity") > -1);
146: }
147:
148: /**
149: * Define this column to be an expression.
150: *
151: * The major difference to setColumnName() is, that the name will internally
152: * not be stored in lowercase
153: * (But can be used in a SELECT anyway)
154: */
155: public void setExpression(String anExpression) {
156: this .name = anExpression;
157: this .isExpression = true;
158: this .isPk = false;
159: this .type = Types.OTHER;
160: }
161:
162: /**
163: * Creates a deep copy of this ColumnIdentifier.
164: * @return a copy of this identifier
165: */
166: public ColumnIdentifier createCopy() {
167: ColumnIdentifier result = new ColumnIdentifier();
168: result.name = this .name;
169: result.hashCode = this .hashCode;
170: result.digits = this .digits;
171: result.isExpression = this .isExpression;
172: result.isNullable = this .isNullable;
173: result.isPk = this .isPk;
174: result.size = this .size;
175: result.type = this .type;
176: result.dbmsType = this .dbmsType;
177: result.isUpdateable = this .isUpdateable;
178: result.comment = this .comment;
179: result.defaultValue = this .defaultValue;
180: result.columnClassName = this .columnClassName;
181: result.columnTypeName = this .columnTypeName;
182: result.position = this .position;
183: return result;
184: }
185:
186: public String getColumnName(WbConnection con) {
187: if (con == null)
188: return getColumnName();
189: return con.getMetadata().quoteObjectname(name);
190: }
191:
192: public String getColumnName() {
193: return this .name;
194: }
195:
196: /**
197: * Define the name of this column.
198: *
199: * This will also reset the PK and Nullable attributes. isPkColumn()
200: * and isNullable() will return false after setting the name.
201: *
202: * @param aName the (new) name for this identifier
203: */
204: public void setColumnName(String aName) {
205: this .name = aName;
206: this .isExpression = false;
207: this .isPk = false;
208: this .isNullable = true;
209: this .hashCode = (name == null ? -1 : StringUtil
210: .trimQuotes(name).toLowerCase().hashCode());
211: }
212:
213: /**
214: * Set the JDBC datatype.
215: *
216: * @see java.sql.Types
217: */
218: public void setDataType(int aType) {
219: this .type = aType;
220: }
221:
222: /**
223: * Returns the java.sql.Types data type as returned
224: * by the jdbc driver. If no type has been defined
225: * Types.OTHER will be returned
226: *
227: * @return the current datatype
228: */
229: public int getDataType() {
230: return this .type;
231: }
232:
233: public String toString() {
234: return this .name;
235: }
236:
237: /**
238: * Compare two identifiers.
239: * The comparison is only done on the name column and is case-insesitive.
240: *
241: * If the object is not a ColumnIdentifier it returns false
242: *
243: * @param other the object to compare
244: * @return true if the other ColumnIdentifier has the same name
245: */
246: public boolean equals(Object other) {
247: try {
248: ColumnIdentifier col = (ColumnIdentifier) other;
249: return StringUtil.equalStringIgnoreCase(StringUtil
250: .trimQuotes(this .name), StringUtil
251: .trimQuotes(col.name));
252: } catch (Exception e) {
253: return false;
254: }
255: }
256:
257: public int hashCode() {
258: return hashCode;
259: }
260:
261: public String getComment() {
262: return comment;
263: }
264:
265: public void setComment(String comment) {
266: this .comment = comment;
267: }
268:
269: public String getDefaultValue() {
270: return defaultValue;
271: }
272:
273: public void setDefaultValue(String defaultValue) {
274: this .defaultValue = defaultValue;
275: }
276:
277: public int getPosition() {
278: return position;
279: }
280:
281: public void setPosition(int pos) {
282: this .position = pos;
283: }
284:
285: public String getColumnClassName() {
286: return columnClassName;
287: }
288:
289: public void setColumnClassName(String columnClass) {
290: if (columnClass != null && columnClass.endsWith("[]")) {
291: // Workaround for long[]
292: if (columnClass.startsWith("long")) {
293: this .columnClassName = "[J";
294: } else if (Character.isLowerCase(columnClass.charAt(0))) {
295: // If it's a lower case class name we assume a native array type
296: this .columnClassName = "["
297: + columnClass.toUpperCase().charAt(0);
298: }
299: } else {
300: this .columnClassName = columnClass;
301: }
302: this .columnClass = null;
303: if (this .columnClassName == null)
304: return;
305:
306: try {
307: this .columnClass = Class.forName(this .columnClassName);
308: } catch (Exception e) {
309: //LogMgr.logDebug("ColumnIdentifier.setColumnClassName()", "Could not obtain column class", e);
310: this .columnClass = null;
311: }
312: }
313:
314: public Class getColumnClass() {
315: if (this .columnClass != null)
316: return this .columnClass;
317:
318: switch (this .type) {
319: case Types.BIGINT:
320: case Types.INTEGER:
321: return Long.class;
322:
323: case Types.SMALLINT:
324: return Integer.class;
325:
326: case Types.NUMERIC:
327: case Types.DECIMAL:
328: return BigDecimal.class;
329:
330: case Types.DOUBLE:
331: return Double.class;
332:
333: case Types.REAL:
334: case Types.FLOAT:
335: return Float.class;
336:
337: case Types.CHAR:
338: case Types.VARCHAR:
339: case Types.LONGVARCHAR:
340: return String.class;
341:
342: case Types.DATE:
343: return java.sql.Date.class;
344:
345: case Types.TIMESTAMP:
346: return Timestamp.class;
347:
348: default:
349: return Object.class;
350: }
351:
352: }
353:
354: public String getColumnTypeName() {
355: if (this .columnTypeName == null) {
356: return SqlUtil.getTypeName(this .type);
357: }
358: return this .columnTypeName;
359: }
360:
361: public void setColumnTypeName(String columnTypeName) {
362: this .columnTypeName = columnTypeName;
363: }
364:
365: public boolean isUpdateable() {
366: return isUpdateable;
367: }
368:
369: public void setUpdateable(boolean isUpdateable) {
370: this .isUpdateable = isUpdateable;
371: }
372:
373: public int compareTo(ColumnIdentifier other) {
374: if (other == null)
375: return 1;
376: if (this .name == null)
377: return -1;
378: return StringUtil.trimQuotes(name).compareToIgnoreCase(
379: StringUtil.trimQuotes(other.name));
380: }
381:
382: public static void sortByPosition(List<ColumnIdentifier> columnList) {
383: Comparator<ColumnIdentifier> c = new Comparator<ColumnIdentifier>() {
384: public int compare(ColumnIdentifier o1, ColumnIdentifier o2) {
385: int pos1 = o1.getPosition();
386: int pos2 = o2.getPosition();
387: return pos1 - pos2;
388: }
389: };
390: Collections.sort(columnList, c);
391: }
392: }
|