View Javadoc

1   package org.apache.torque.engine.database.model;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.util.ArrayList;
23  import java.util.Collections;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import org.apache.commons.collections.map.ListOrderedMap;
29  import org.apache.commons.lang.StringUtils;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.torque.engine.EngineException;
33  import org.apache.torque.engine.platform.Platform;
34  import org.apache.torque.engine.platform.PlatformDefaultImpl;
35  import org.xml.sax.Attributes;
36  
37  /**
38   * A Class for holding data about a column used in an Application.
39   * 
40   * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
41   * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
42   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
43   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
44   * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
45   * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a>
46   * @author <a href="mailto:monroe@dukece.com>Greg Monroe</a>
47   * @version $Id: Column.java,v 1.1 2007-10-21 07:57:27 abyrne Exp $
48   */
49  public class Column {
50  	private static final SchemaType DEFAULT_TYPE = SchemaType.VARCHAR;
51  	/** Logging class from commons.logging */
52  	private static Log log = LogFactory.getLog(Column.class);
53  	private String name;
54  	private String description;
55  	private Domain domain = new Domain();
56  	private String javaName = null;
57  	private String javaNamingMethod;
58  	private boolean isNotNull = false;
59  	private boolean isProtected = false;
60  	private String javaType;
61  	private Table parentTable;
62  	private int position;
63  	private boolean isPrimaryKey = false;
64  	private boolean isUnique = false;
65  	private boolean isAutoIncrement = false;
66  	private List referrers;
67  	// only one type is supported currently, which assumes the
68  	// column either contains the classnames or a key to
69  	// classnames specified in the schema. Others may be
70  	// supported later.
71  	private String inheritanceType;
72  	private boolean isInheritance;
73  	private boolean isEnumeratedClasses;
74  	private List inheritanceList;
75  	private boolean needsTransactionInPostgres;
76  	/**
77  	 * The type from java.sql.Types
78  	 */
79  	private int jdbcType;
80  
81  	/** generate is... setters for boolean columns if true */
82  	private boolean correctGetters = false;
83  
84  	/** class name to do input validation on this column */
85  	private String inputValidator = null;
86  	private Map options;
87  
88  	/**
89  	 * Creates a new instance with a <code>null</code> name.
90  	 */
91  	public Column() {
92  		this(null);
93  	}
94  
95  	/**
96  	 * Creates a new column and set the name
97  	 * 
98  	 * @param name
99  	 *            column name
100 	 */
101 	public Column(String name) {
102 		this.name = name;
103 		options = Collections.synchronizedMap(new ListOrderedMap());
104 	}
105 
106 	/**
107 	 * Return a comma delimited string listing the specified columns.
108 	 * 
109 	 * @param columns
110 	 *            Either a list of <code>Column</code> objects, or a list of <code>String</code> objects with column
111 	 *            names.
112 	 */
113 	public static String makeList(List columns) {
114 		Object obj = columns.get(0);
115 		boolean isColumnList = (obj instanceof Column);
116 		if (isColumnList) {
117 			obj = ((Column) obj).getName();
118 		}
119 		StringBuffer buf = new StringBuffer((String) obj);
120 		for (int i = 1; i < columns.size(); i++) {
121 			obj = columns.get(i);
122 			if (isColumnList) {
123 				obj = ((Column) obj).getName();
124 			}
125 			buf.append(", ").append(obj);
126 		}
127 		return buf.toString();
128 	}
129 
130 	/**
131 	 * Imports a column from an XML specification
132 	 */
133 	public void loadFromXML(Attributes attrib) {
134 		String dom = attrib.getValue("domain");
135 		if (StringUtils.isNotEmpty(dom)) {
136 			domain = new Domain(getTable().getDatabase().getDomain(dom));
137 		} else {
138 			domain = new Domain(getPlatform().getDomainForSchemaType(DEFAULT_TYPE));
139 			setType(attrib.getValue("type"));
140 		}
141 		// Name
142 		name = attrib.getValue("name");
143 
144 		javaName = attrib.getValue("javaName");
145 		javaType = attrib.getValue("javaType");
146 		if (javaType != null && javaType.length() == 0) {
147 			javaType = null;
148 		}
149 
150 		// retrieves the method for converting from specified name to
151 		// a java name.
152 		javaNamingMethod = attrib.getValue("javaNamingMethod");
153 		if (javaNamingMethod == null) {
154 			javaNamingMethod = parentTable.getDatabase().getDefaultJavaNamingMethod();
155 		}
156 
157 		// Primary Key
158 		String primaryKey = attrib.getValue("primaryKey");
159 		// Avoid NullPointerExceptions on string comparisons.
160 		isPrimaryKey = ("true".equals(primaryKey));
161 
162 		// If this column is a primary key then it can't be null.
163 		if ("true".equals(primaryKey)) {
164 			isNotNull = true;
165 		}
166 
167 		// HELP: Should primary key, index, and/or idMethod="native"
168 		// affect isNotNull? If not, please document why here.
169 		String notNull = attrib.getValue("required");
170 		isNotNull = (notNull != null && "true".equals(notNull));
171 
172 		// AutoIncrement/Sequences
173 		String autoIncrement = attrib.getValue("autoIncrement");
174 		// autoincrement is false per default,
175 		// except if the column is a primary key
176 		// and the idMethod is native
177 		// and the platform's default id Method is identity
178 		// and autoIncrement is not excplicitly set to false
179 		isAutoIncrement = ("true".equals(autoIncrement) || (isPrimaryKey() && IDMethod.NATIVE.equals(getTable().getIdMethod()) && Platform.IDENTITY.equals(getPlatform().getNativeIdMethod()) && (!"false".equals(autoIncrement))));
180 		// Default column value.
181 		domain.replaceDefaultValue(attrib.getValue("default"));
182 
183 		domain.replaceSize(attrib.getValue("size"));
184 		domain.replaceScale(attrib.getValue("scale"));
185 
186 		inheritanceType = attrib.getValue("inheritance");
187 		isInheritance = (inheritanceType != null && !inheritanceType.equals("false"));
188 
189 		this.inputValidator = attrib.getValue("inputValidator");
190 		description = attrib.getValue("description");
191 
192 		isProtected = ("true".equals(attrib.getValue("protected")));
193 	}
194 
195 	/**
196 	 * Returns table.column
197 	 */
198 	public String getFullyQualifiedName() {
199 		return (parentTable.getName() + '.' + name);
200 	}
201 
202 	/**
203 	 * Get the name of the column
204 	 */
205 	public String getName() {
206 		return name;
207 	}
208 
209 	/**
210 	 * Set the name of the column
211 	 */
212 	public void setName(String newName) {
213 		name = newName;
214 	}
215 
216 	/**
217 	 * Get the description for the Table
218 	 */
219 	public String getDescription() {
220 		return description;
221 	}
222 
223 	/**
224 	 * Set the description for the Table
225 	 * 
226 	 * @param newDescription
227 	 *            description for the Table
228 	 */
229 	public void setDescription(String newDescription) {
230 		description = newDescription;
231 	}
232 
233 	/**
234 	 * Get name to use in Java sources to build method names.
235 	 * 
236 	 * @return the capitalised javaName
237 	 */
238 	public String getJavaName() {
239 		if (javaName == null) {
240 			List inputs = new ArrayList(2);
241 			inputs.add(name);
242 			inputs.add(javaNamingMethod);
243 			try {
244 				javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR, inputs);
245 			} catch (EngineException e) {
246 				log.error(e, e);
247 			}
248 		}
249 		return StringUtils.capitalize(javaName);
250 	}
251 
252 	/**
253 	 * Returns the name for the getter method to retrieve the value of this column
254 	 * 
255 	 * @return A getter method name for this column.
256 	 * @since 3.2
257 	 */
258 	public String getGetterName() {
259 		if (("boolean".equalsIgnoreCase(getJavaNative()) && isCorrectGetters())) {
260 			return "is" + StringUtils.capitalize(getJavaName());
261 		} else {
262 			return "get" + StringUtils.capitalize(getJavaName());
263 		}
264 	}
265 
266 	/**
267 	 * Returns the name for the setter method to set the value of this column
268 	 * 
269 	 * @return A setter method name for this column.
270 	 * @since 3.2
271 	 */
272 	public String getSetterName() {
273 		return "set" + StringUtils.capitalize(getJavaName());
274 	}
275 
276 	/**
277 	 * Get variable name to use in Java sources (= uncapitalised java name)
278 	 */
279 	public String getUncapitalisedJavaName() {
280 		return StringUtils.uncapitalize(getJavaName());
281 	}
282 
283 	/**
284 	 * Returns the name of the constant that is used for the column in the Peer class, e.g., RecordPeer.COLVARNAME.
285 	 * Generally this will be a straight conversion to upper case. But if the column name is equals to TABLE_NAME or
286 	 * DATABASE_NAME (Torque predefined vars), the column name will have an _ prefixed, e.g. _TABLE_NAME.
287 	 * <p>
288 	 * TODO: Handle delimited column names that have non-Java identifier characters in them.
289 	 * 
290 	 * @return The name to use in defining the Peer class column variable.
291 	 */
292 	public String getPeerJavaName() {
293 		String peerName = name.toUpperCase();
294 		if (peerName.equals("TABLE_NAME") || peerName.equals("DATABASE_NAME")) {
295 			peerName = "_" + peerName;
296 		}
297 		return peerName;
298 	}
299 
300 	/**
301 	 * Set the name to use in Java sources.
302 	 */
303 	public void setJavaName(String javaName) {
304 		this.javaName = javaName;
305 	}
306 
307 	/**
308 	 * Returns whether the type in the java object should be an object or primitive.
309 	 */
310 	public String getJavaType() {
311 		return javaType;
312 	}
313 
314 	/**
315 	 * Get the location of this column within the table (one-based).
316 	 * 
317 	 * @return value of position.
318 	 */
319 	public int getPosition() {
320 		return position;
321 	}
322 
323 	/**
324 	 * Get the location of this column within the table (one-based).
325 	 * 
326 	 * @param v
327 	 *            Value to assign to position.
328 	 */
329 	public void setPosition(int v) {
330 		this.position = v;
331 	}
332 
333 	/**
334 	 * Set the parent Table of the column
335 	 */
336 	public void setTable(Table parent) {
337 		parentTable = parent;
338 	}
339 
340 	/**
341 	 * Get the parent Table of the column
342 	 */
343 	public Table getTable() {
344 		return parentTable;
345 	}
346 
347 	/**
348 	 * Returns the Name of the table the column is in
349 	 */
350 	public String getTableName() {
351 		return parentTable.getName();
352 	}
353 
354 	/**
355 	 * A utility function to create a new column from attrib and add it to this table.
356 	 */
357 	public Inheritance addInheritance(Attributes attrib) {
358 		Inheritance inh = new Inheritance();
359 		inh.loadFromXML(attrib);
360 		addInheritance(inh);
361 
362 		return inh;
363 	}
364 
365 	/**
366 	 * Adds a new inheritance definition to the inheritance list and set the parent column of the inheritance to the
367 	 * current column
368 	 */
369 	public void addInheritance(Inheritance inh) {
370 		inh.setColumn(this);
371 		if (inheritanceList == null) {
372 			inheritanceList = new ArrayList();
373 			isEnumeratedClasses = true;
374 		}
375 		inheritanceList.add(inh);
376 	}
377 
378 	/**
379 	 * Get the inheritance definitions.
380 	 */
381 	public List getChildren() {
382 		return inheritanceList;
383 	}
384 
385 	/**
386 	 * Determine if this column is a normal property or specifies a the classes that are represented in the table
387 	 * containing this column.
388 	 */
389 	public boolean isInheritance() {
390 		return isInheritance;
391 	}
392 
393 	/**
394 	 * Determine if possible classes have been enumerated in the xml file.
395 	 */
396 	public boolean isEnumeratedClasses() {
397 		return isEnumeratedClasses;
398 	}
399 
400 	/**
401 	 * Return the isNotNull property of the column
402 	 */
403 	public boolean isNotNull() {
404 		return isNotNull;
405 	}
406 
407 	/**
408 	 * Set the isNotNull property of the column
409 	 */
410 	public void setNotNull(boolean status) {
411 		isNotNull = status;
412 	}
413 
414 	/**
415 	 * Return NOT NULL String for this column
416 	 * 
417 	 * @return "NOT NULL" if null values are not allowed or an empty String.
418 	 */
419 	public String getNotNullString() {
420 		return getTable().getDatabase().getPlatform().getNullString(this.isNotNull());
421 	}
422 
423 	/**
424 	 * Return the isProtected property of the column
425 	 */
426 	public boolean isProtected() {
427 		return isProtected;
428 	}
429 
430 	/**
431 	 * Set the isProtected property of the Column
432 	 */
433 	public void setProtected(boolean prot) {
434 		isProtected = prot;
435 	}
436 
437 	/**
438 	 * Set if the column is a primary key or not
439 	 */
440 	public void setPrimaryKey(boolean pk) {
441 		isPrimaryKey = pk;
442 	}
443 
444 	/**
445 	 * Return true if the column is a primary key
446 	 */
447 	public boolean isPrimaryKey() {
448 		return isPrimaryKey;
449 	}
450 
451 	/**
452 	 * Set true if the column is UNIQUE
453 	 */
454 	public void setUnique(boolean u) {
455 		isUnique = u;
456 	}
457 
458 	/**
459 	 * Get the UNIQUE property
460 	 */
461 	public boolean isUnique() {
462 		return isUnique;
463 	}
464 
465 	/**
466 	 * Return true if the column requires a transaction in Postgres
467 	 */
468 	public boolean requiresTransactionInPostgres() {
469 		return needsTransactionInPostgres;
470 	}
471 
472 	/**
473 	 * Utility method to determine if this column is a foreign key.
474 	 */
475 	public boolean isForeignKey() {
476 		return (getForeignKey() != null);
477 	}
478 
479 	/**
480 	 * Determine if this column is a foreign key that refers to the same table as another foreign key column in this
481 	 * table.
482 	 */
483 	public boolean isMultipleFK() {
484 		ForeignKey fk = getForeignKey();
485 		if (fk != null) {
486 			Iterator fks = parentTable.getForeignKeys().iterator();
487 			while (fks.hasNext()) {
488 				ForeignKey key = (ForeignKey) fks.next();
489 				if (key.getForeignTableName().equals(fk.getForeignTableName()) && !key.getLocalColumns().contains(this.name)) {
490 					return true;
491 				}
492 			}
493 		}
494 
495 		// No multiple foreign keys.
496 		return false;
497 	}
498 
499 	/**
500 	 * get the foreign key object for this column if it is a foreign key or part of a foreign key
501 	 */
502 	public ForeignKey getForeignKey() {
503 		return parentTable.getForeignKey(this.name);
504 	}
505 
506 	/**
507 	 * Utility method to get the related table of this column if it is a foreign key or part of a foreign key
508 	 */
509 	public String getRelatedTableName() {
510 		ForeignKey fk = getForeignKey();
511 		return (fk == null ? null : fk.getForeignTableName());
512 	}
513 
514 	/**
515 	 * Utility method to get the related column of this local column if this column is a foreign key or part of a
516 	 * foreign key.
517 	 */
518 	public String getRelatedColumnName() {
519 		ForeignKey fk = getForeignKey();
520 		if (fk == null) {
521 			return null;
522 		} else {
523 			return fk.getLocalForeignMapping().get(this.name).toString();
524 		}
525 	}
526 
527 	/**
528 	 * Adds the foreign key from another table that refers to this column.
529 	 */
530 	public void addReferrer(ForeignKey fk) {
531 		if (referrers == null) {
532 			referrers = new ArrayList(5);
533 		}
534 		referrers.add(fk);
535 	}
536 
537 	/**
538 	 * Get list of references to this column.
539 	 */
540 	public List getReferrers() {
541 		if (referrers == null) {
542 			referrers = new ArrayList(5);
543 		}
544 		return referrers;
545 	}
546 
547 	/**
548 	 * Sets the colunm type
549 	 */
550 	public void setType(String torqueType) {
551 		SchemaType type = SchemaType.getEnum(torqueType);
552 		if (type == null) {
553 			log.warn("SchemaType " + torqueType + " does not exist");
554 			type = Column.DEFAULT_TYPE;
555 		}
556 		setType(type);
557 	}
558 
559 	/**
560 	 * Sets the colunm type
561 	 */
562 	public void setType(SchemaType torqueType) {
563 		domain = new Domain(getPlatform().getDomainForSchemaType(torqueType));
564 		if (torqueType.equals(SchemaType.VARBINARY) || torqueType.equals(SchemaType.BLOB)) {
565 			needsTransactionInPostgres = true;
566 		}
567 	}
568 
569 	/**
570 	 * Returns the column jdbc type as an object
571 	 * 
572 	 * @deprecated the type conversion is handled by the platform package (since torque 3.2)
573 	 */
574 	public Object getType() {
575 		return TypeMap.getJdbcType(domain.getType()).getName();
576 	}
577 
578 	/**
579 	 * Returns the column type as given in the schema as an object
580 	 */
581 	public Object getTorqueType() {
582 		return domain.getType().getName();
583 	}
584 
585 	/**
586 	 * Utility method to see if the column is a string
587 	 * 
588 	 * @deprecated will be removed after the 3.3 release
589 	 */
590 	public boolean isString() {
591 		return (domain.getType().getName().indexOf("CHAR") != -1);
592 	}
593 
594 	/**
595 	 * Utility method to return the value as an element to be usable in an SQL insert statement. This is used from the
596 	 * SQL loader task
597 	 */
598 	public boolean needEscapedValue() {
599 		String torqueType = domain.getType().getName();
600 		return (torqueType != null) && (torqueType.equals("VARCHAR") || torqueType.equals("LONGVARCHAR") || torqueType.equals("DATE") || torqueType.equals("DATETIME") || torqueType.equals("TIMESTAMP") || torqueType.equals("TIME") || torqueType.equals("CHAR") || torqueType.equals("CLOB"));
601 	}
602 
603 	/**
604 	 * String representation of the column. This is an xml representation.
605 	 * 
606 	 * @return string representation in xml
607 	 */
608 	public String toString() {
609 		StringBuffer result = new StringBuffer();
610 		result.append("    <column name=\"").append(name).append('"');
611 
612 		if (javaName != null) {
613 			result.append(" javaName=\"").append(javaName).append('"');
614 		}
615 
616 		if (isPrimaryKey) {
617 			result.append(" primaryKey=\"").append(isPrimaryKey).append('"');
618 		}
619 
620 		if (isNotNull) {
621 			result.append(" required=\"true\"");
622 		} else {
623 			result.append(" required=\"false\"");
624 		}
625 
626 		result.append(" type=\"").append(domain.getType().getName()).append('"');
627 
628 		if (domain.getSize() != null) {
629 			result.append(" size=\"").append(domain.getSize()).append('"');
630 		}
631 
632 		if (domain.getScale() != null) {
633 			result.append(" scale=\"").append(domain.getScale()).append('"');
634 		}
635 
636 		if (domain.getDefaultValue() != null) {
637 			result.append(" default=\"").append(domain.getDefaultValue()).append('"');
638 		}
639 
640 		if (isInheritance()) {
641 			result.append(" inheritance=\"").append(inheritanceType).append('"');
642 		}
643 
644 		// Close the column.
645 		result.append(" />\n");
646 
647 		return result.toString();
648 	}
649 
650 	/**
651 	 * Returns the size of the column
652 	 */
653 	public String getSize() {
654 		return domain.getSize();
655 	}
656 
657 	/**
658 	 * Set the size of the column
659 	 */
660 	public void setSize(String newSize) {
661 		domain.setSize(newSize);
662 	}
663 
664 	/**
665 	 * Try to determine the precision of the field from the size attribute. If size attribute is an integer number, it
666 	 * will be returned. If size attribute is of the format "Precision,Scale", then Precision will be returned. If size
667 	 * is null or the size value is not an valid integer, null is returned.
668 	 * <p>
669 	 * Note: Unparseable values will be logged as a warning.
670 	 * 
671 	 * @return The precision portion of the size attribute.
672 	 */
673 	public String getPrecision() {
674 		String size = getSize();
675 		if (size == null) {
676 			return size;
677 		}
678 		int cLoc = size.indexOf(',');
679 		if (cLoc > 0) {
680 			size = size.substring(0, cLoc);
681 		}
682 		try {
683 			Integer.parseInt(size);
684 		} catch (NumberFormatException e) {
685 			log.warn("getPrecision(): Size attribute found (" + getSize() + ") was not an integer number, using default of null!");
686 			size = null;
687 		}
688 		return size;
689 	}
690 
691 	/**
692 	 * Try to determine the scale of the field from the scale and size attribute. If scale attribute is an integer
693 	 * number, it will be returned. If size attribute is of the format "Precision,Scale", then Scale will be returned.
694 	 * If scale and size attributes are null or the scale value found is not an valid integer, a null value is returned.
695 	 * <p>
696 	 * Note: Unparseable values will be logged as a warning.
697 	 * 
698 	 * @return The precision portion of the size attribute.
699 	 */
700 	public String getScale() {
701 		String scale = domain.getScale();
702 		// Check for scale on size attribute if no scale attribute
703 		if (scale == null) {
704 			scale = getSize();
705 			if (scale == null) // No scale or size attribute set.
706 			{
707 				return scale;
708 			}
709 			int cLoc = scale.indexOf(',');
710 			if (cLoc < 0) // Size did not have "P,S" format
711 			{
712 				return null;
713 			}
714 			scale = scale.substring(cLoc + 1);
715 		}
716 
717 		// Validate that scale string found is integer.
718 		try {
719 			Integer.parseInt(scale);
720 		} catch (NumberFormatException e) {
721 			log.warn("getScale(): Scale (or size=\"p,s\") attribute found (" + scale + ") was not an integer number, using default of null.");
722 			scale = null;
723 		}
724 		return scale;
725 	}
726 
727 	/**
728 	 * Set the scale of the column
729 	 */
730 	public void setScale(String newScale) {
731 		domain.setScale(newScale);
732 	}
733 
734 	/**
735 	 * Return the size and scale in brackets for use in an sql schema.
736 	 * 
737 	 * @return size and scale or an empty String if there are no values available.
738 	 */
739 	public String printSize() {
740 		return domain.printSize();
741 	}
742 
743 	/**
744 	 * Return a string that will give this column a default value.
745 	 * 
746 	 * @deprecated
747 	 */
748 	public String getDefaultSetting() {
749 		return domain.getDefaultSetting();
750 	}
751 
752 	/**
753 	 * Set a string that will give this column a default value.
754 	 */
755 	public void setDefaultValue(String def) {
756 		domain.setDefaultValue(def);
757 	}
758 
759 	/**
760 	 * Get a string that will give this column a default value.
761 	 */
762 	public String getDefaultValue() {
763 		return domain.getDefaultValue();
764 	}
765 
766 	/**
767 	 * Returns the class name to do input validation
768 	 */
769 	public String getInputValidator() {
770 		return this.inputValidator;
771 	}
772 
773 	/**
774 	 * Return auto increment/sequence string for the target database. We need to pass in the props for the target
775 	 * database!
776 	 */
777 	public boolean isAutoIncrement() {
778 		return isAutoIncrement;
779 	}
780 
781 	/**
782 	 * Set the auto increment value. Use isAutoIncrement() to find out if it is set or not.
783 	 */
784 	public void setAutoIncrement(boolean value) {
785 		isAutoIncrement = value;
786 	}
787 
788 	public String getAutoIncrementString() {
789 		if (isAutoIncrement() && IDMethod.NATIVE.equals(getTable().getIdMethod())) {
790 			return getPlatform().getAutoIncrement();
791 		}
792 		return "";
793 	}
794 
795 	/**
796 	 * Set the column type from a string property (normally a string from an sql input file)
797 	 */
798 	public void setTypeFromString(String typeName, String size) {
799 		String tn = typeName.toUpperCase();
800 		setType(tn);
801 
802 		if (size != null) {
803 			domain.setSize(size);
804 		}
805 
806 		if (tn.indexOf("CHAR") != -1) {
807 			domain.setType(SchemaType.VARCHAR);
808 		} else if (tn.indexOf("INT") != -1) {
809 			domain.setType(SchemaType.INTEGER);
810 		} else if (tn.indexOf("FLOAT") != -1) {
811 			domain.setType(SchemaType.FLOAT);
812 		} else if (tn.indexOf("DATE") != -1) {
813 			domain.setType(SchemaType.DATE);
814 		} else if (tn.indexOf("TIME") != -1) {
815 			domain.setType(SchemaType.TIMESTAMP);
816 		} else if (tn.indexOf("BINARY") != -1) {
817 			domain.setType(SchemaType.LONGVARBINARY);
818 		} else {
819 			domain.setType(SchemaType.VARCHAR);
820 		}
821 	}
822 
823 	/**
824 	 * Return a string representation of the Java object which corresponds to the JDBC type of this column. Use in the
825 	 * generation of MapBuilders.
826 	 */
827 	public String getJavaObject() {
828 		return TypeMap.getJavaObject(domain.getType());
829 	}
830 
831 	/**
832 	 * Return a string representation of the primitive java type which corresponds to the JDBC type of this column.
833 	 * 
834 	 * @return string representation of the primitive java type
835 	 */
836 	public String getJavaPrimitive() {
837 		return TypeMap.getJavaNative(domain.getType());
838 	}
839 
840 	/**
841 	 * Return a string representation of the native java type which corresponds to the JDBC type of this column. Use in
842 	 * the generation of Base objects. This method is used by torque, so it returns Key types for primaryKey and
843 	 * foreignKey columns
844 	 * 
845 	 * @return java datatype used by torque
846 	 */
847 	public String getJavaNative() {
848 		String jtype = TypeMap.getJavaNativeObject(domain.getType());
849 		if (isUsePrimitive()) {
850 			jtype = TypeMap.getJavaNative(domain.getType());
851 		}
852 
853 		return jtype;
854 	}
855 
856 	/**
857 	 * Return Village asX() method which corresponds to the JDBC type which represents this column.
858 	 */
859 	public String getVillageMethod() {
860 		String vmethod = TypeMap.getVillageObjectMethod(domain.getType());
861 		if (isUsePrimitive()) {
862 			vmethod = TypeMap.getVillageMethod(domain.getType());
863 		}
864 
865 		return vmethod;
866 	}
867 
868 	/**
869 	 * Return ParameterParser getX() method which corresponds to the JDBC type which represents this column.
870 	 */
871 	public String getParameterParserMethod() {
872 		return TypeMap.getPPMethod(domain.getType());
873 	}
874 
875 	/**
876 	 * Returns true if the column type is boolean in the java object and a numeric (1 or 0) in the db.
877 	 */
878 	public boolean isBooleanInt() {
879 		return TypeMap.isBooleanInt(domain.getType());
880 	}
881 
882 	/**
883 	 * Returns true if the column type is boolean in the java object and a String ("Y" or "N") in the db.
884 	 */
885 	public boolean isBooleanChar() {
886 		return TypeMap.isBooleanChar(domain.getType());
887 	}
888 
889 	/**
890 	 * Returns true if the column type is boolean in the java object and a Bit ("1" or "0") in the db.
891 	 */
892 	public boolean isBit() {
893 		return TypeMap.isBit(domain.getType());
894 	}
895 
896 	/**
897 	 * returns true, if the columns java native type is an boolean, byte, short, int, long, float, double, char
898 	 */
899 	public boolean isPrimitive() {
900 		String t = getJavaNative();
901 		return "boolean".equals(t) || "byte".equals(t) || "short".equals(t) || "int".equals(t) || "long".equals(t) || "float".equals(t) || "double".equals(t) || "char".equals(t);
902 	}
903 
904 	public boolean isUsePrimitive() {
905 		String s = getJavaType();
906 		return (s != null && s.equals("primitive")) || (s == null && !"object".equals(getTable().getDatabase().getDefaultJavaType()));
907 	}
908 
909 	/**
910 	 * @return Returns the domain.
911 	 */
912 	public Domain getDomain() {
913 		return domain;
914 	}
915 
916 	/**
917 	 * @param domain
918 	 *            The domain to set.
919 	 */
920 	public void setDomain(Domain domain) {
921 		this.domain = domain;
922 	}
923 
924 	private Platform getPlatform() {
925 		try {
926 			return getTable().getDatabase().getPlatform();
927 		} catch (Exception ex) {
928 			log.warn("could not load platform implementation");
929 		}
930 		return new PlatformDefaultImpl();
931 	}
932 
933 	public String getSqlString() {
934 		List resultList = new ArrayList();
935 		resultList.add(getName());
936 
937 		String type = getDomain().getSqlType();
938 
939 		if (getPlatform().hasSize(getDomain().getSqlType())) {
940 			type += getDomain().printSize();
941 		}
942 
943 		resultList.add(type);
944 
945 		String defaultStr = getPlatform().filterInvalidDefaultValues(getDomain().getDefaultValue());
946 		if (StringUtils.isNotEmpty(defaultStr)) {
947 
948 			resultList.add("default");
949 
950 			if (TypeMap.isTextType(getDomain().getType()) && !getPlatform().isSpecialDefault(defaultStr)) {
951 				// TODO: Properly SQL-escape the text.
952 				resultList.add(new StringBuffer().append('\'').append(getDefaultValue()).append('\''));
953 			} else {
954 				resultList.add(getDefaultValue());
955 			}
956 		}
957 		if (getPlatform().createNotNullBeforeAutoincrement()) {
958 			if (StringUtils.isNotEmpty(getNotNullString())) {
959 				resultList.add(getNotNullString());
960 			}
961 		}
962 		if (StringUtils.isNotEmpty(getAutoIncrementString())) {
963 			resultList.add(getAutoIncrementString());
964 		}
965 		if (!getPlatform().createNotNullBeforeAutoincrement()) {
966 			if (StringUtils.isNotEmpty(getNotNullString())) {
967 				resultList.add(getNotNullString());
968 			}
969 		}
970 		return StringUtils.join(resultList.iterator(), ' ');
971 	}
972 
973 	/**
974 	 * Return the correctGetters property of the column
975 	 * 
976 	 * @return The currentValue of the correctGetters property.
977 	 * @since 3.2
978 	 */
979 	public boolean isCorrectGetters() {
980 		return correctGetters;
981 	}
982 
983 	/**
984 	 * Set the correctGetters property of the column. If set to true, the column returns is&lt;xxx&gt; as the getter
985 	 * name which is correct for the Bean Specs but incompatible to pre-3.2 releases.
986 	 * 
987 	 * @param correctGetters
988 	 *            The new value of the correctGetters property.
989 	 * @since 3.2
990 	 */
991 	public void setCorrectGetters(boolean correctGetters) {
992 		this.correctGetters = correctGetters;
993 	}
994 
995 	/**
996 	 * Get the value of the inheritance attribute defined in the schema XML.
997 	 * 
998 	 * @return Returns the inheritanceType.
999 	 */
1000 	public String getInheritanceType() {
1001 		return inheritanceType;
1002 	}
1003 
1004 	/**
1005 	 * Add an XML Specified option key/value pair to this element's option set.
1006 	 * 
1007 	 * @param key
1008 	 *            the key of the option.
1009 	 * @param value
1010 	 *            the value of the option.
1011 	 */
1012 	public void addOption(String key, String value) {
1013 		options.put(key, value);
1014 	}
1015 
1016 	/**
1017 	 * Get the value that was associated with this key in an XML option element.
1018 	 * 
1019 	 * @param key
1020 	 *            the key of the option.
1021 	 * @return The value for the key or a null.
1022 	 */
1023 	public String getOption(String key) {
1024 		return (String) options.get(key);
1025 	}
1026 
1027 	/**
1028 	 * Gets the full ordered hashtable array of items specified by XML option statements under this element.
1029 	 * <p>
1030 	 * 
1031 	 * Note, this is not thread save but since it's only used for generation which is single threaded, there should be
1032 	 * minimum danger using this in Velocity.
1033 	 * 
1034 	 * @return An Map of all options. Will not be null but may be empty.
1035 	 */
1036 	public Map getOptions() {
1037 		return options;
1038 	}
1039 
1040 	public int getJdbcType() {
1041 		return jdbcType;
1042 	}
1043 
1044 	public void setJdbcType(int jdbcType) {
1045 		this.jdbcType = jdbcType;
1046 	}
1047 }