1 package org.apache.torque.engine.database.model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 import java.util.ArrayList;
20 import java.util.Hashtable;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import org.apache.commons.lang.StringUtils;
25
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28
29 import org.apache.torque.engine.EngineException;
30
31 import org.xml.sax.Attributes;
32
33 /***
34 * Data about a table used in an application.
35 *
36 * @author <a href="mailto:leon@opticode.co.za">Leon Messerschmidt</a>
37 * @author <a href="mailto:jvanzyl@apache.org">Jason van Zyl</a>
38 * @author <a href="mailto:mpoeschl@marmot.at>Martin Poeschl</a>
39 * @author <a href="mailto:jmcnally@collab.net>John McNally</a>
40 * @author <a href="mailto:dlr@collab.net>Daniel Rall</a>
41 * @author <a href="mailto:byron_foster@byron_foster@yahoo.com>Byron Foster</a>
42 * @version $Id: Table.java,v 1.8 2004/08/23 00:30:10 seade Exp $
43 */
44 public class Table implements IDMethod
45 {
46 /*** Logging class from commons.logging */
47 private static Log log = LogFactory.getLog(Table.class);
48
49
50 private List columnList;
51 private List foreignKeys;
52 private List indices;
53 private List unices;
54 private List idMethodParameters;
55 private String name;
56 private String description;
57 private String javaName;
58 private String idMethod;
59 private String javaNamingMethod;
60 private Database tableParent;
61 private List referrers;
62 private List foreignTableNames;
63 private boolean containsForeignPK;
64 private Column inheritanceColumn;
65 private boolean skipSql;
66 private boolean abstractValue;
67 private String alias;
68 private String enterface;
69 private String pkg;
70 private String baseClass;
71 private String basePeer;
72 private Hashtable columnsByName;
73 private Hashtable columnsByJavaName;
74 private boolean needsTransactionInPostgres;
75 private boolean heavyIndexing;
76 private boolean forReferenceOnly;
77
78
79 /***
80 * Default Constructor
81 */
82 public Table()
83 {
84 this(null);
85 }
86
87 /***
88 * Constructs a table object with a name
89 *
90 * @param name table name
91 */
92 public Table(String name)
93 {
94 this.name = name;
95 columnList = new ArrayList();
96 foreignKeys = new ArrayList(5);
97 indices = new ArrayList(5);
98 unices = new ArrayList(5);
99 columnsByName = new Hashtable();
100 columnsByJavaName = new Hashtable();
101 }
102
103 /***
104 * Load the table object from an xml tag.
105 *
106 * @param attrib xml attributes
107 * @param defaultIdMethod defined at db level
108 */
109 public void loadFromXML(Attributes attrib, String defaultIdMethod)
110 {
111 name = attrib.getValue("name");
112 javaName = attrib.getValue("javaName");
113 idMethod = attrib.getValue("idMethod");
114
115
116
117 javaNamingMethod = attrib.getValue("javaNamingMethod");
118 if (javaNamingMethod == null)
119 {
120 javaNamingMethod = getDatabase().getDefaultJavaNamingMethod();
121 }
122
123 if ("null".equals(idMethod))
124 {
125 idMethod = defaultIdMethod;
126 }
127 skipSql = "true".equals(attrib.getValue("skipSql"));
128
129 abstractValue = "true".equals(attrib.getValue("abstract"));
130 baseClass = attrib.getValue("baseClass");
131 basePeer = attrib.getValue("basePeer");
132 alias = attrib.getValue("alias");
133 heavyIndexing = "true".equals(attrib.getValue("heavyIndexing"))
134 || (!"false".equals(attrib.getValue("heavyIndexing"))
135 && getDatabase().isHeavyIndexing());
136 description = attrib.getValue("description");
137 enterface = attrib.getValue("interface");
138 }
139
140 /***
141 * <p>A hook for the SAX XML parser to call when this table has
142 * been fully loaded from the XML, and all nested elements have
143 * been processed.</p>
144 *
145 * <p>Performs heavy indexing and naming of elements which weren't
146 * provided with a name.</p>
147 */
148 public void doFinalInitialization()
149 {
150
151
152 if (heavyIndexing)
153 {
154 doHeavyIndexing();
155 }
156
157
158
159 doNaming();
160 }
161
162 /***
163 * <p>Adds extra indices for multi-part primary key columns.</p>
164 *
165 * <p>For databases like MySQL, values in a where clause must
166 * match key part order from the left to right. So, in the key
167 * definition <code>PRIMARY KEY (FOO_ID, BAR_ID)</code>,
168 * <code>FOO_ID</code> <i>must</i> be the first element used in
169 * the <code>where</code> clause of the SQL query used against
170 * this table for the primary key index to be used. This feature
171 * could cause problems under MySQL with heavily indexed tables,
172 * as MySQL currently only supports 16 indices per table (i.e. it
173 * might cause too many indices to be created).</p>
174 *
175 * <p>See <a href="http://www.mysql.com/doc/E/X/EXPLAIN.html">the
176 * manual</a> for a better description of why heavy indexing is
177 * useful for quickly searchable database tables.</p>
178 */
179 private void doHeavyIndexing()
180 {
181 if (log.isDebugEnabled())
182 {
183 log.debug("doHeavyIndex() called on table " + name);
184 }
185
186 List pk = getPrimaryKey();
187 int size = pk.size();
188
189 try
190 {
191
192
193
194 for (int i = 1; i < size; i++)
195 {
196 addIndex(new Index(this, pk.subList(i, size)));
197 }
198 }
199 catch (EngineException e)
200 {
201 log.error(e, e);
202 }
203 }
204
205 /***
206 * Names composing objects which haven't yet been named. This
207 * currently consists of foreign-key and index entities.
208 */
209 private void doNaming()
210 {
211 int i;
212 int size;
213 String name;
214
215
216 try
217 {
218 for (i = 0, size = foreignKeys.size(); i < size; i++)
219 {
220 ForeignKey fk = (ForeignKey) foreignKeys.get(i);
221 name = fk.getName();
222 if (StringUtils.isEmpty(name))
223 {
224 name = acquireConstraintName("FK", i + 1);
225 fk.setName(name);
226 }
227 }
228
229 for (i = 0, size = indices.size(); i < size; i++)
230 {
231 Index index = (Index) indices.get(i);
232 name = index.getName();
233 if (StringUtils.isEmpty(name))
234 {
235 name = acquireConstraintName("I", i + 1);
236 index.setName(name);
237 }
238 }
239
240 for (i = 0, size = unices.size(); i < size; i++)
241 {
242 Unique unique = (Unique) unices.get(i);
243 name = unique.getName();
244 if (StringUtils.isEmpty(name))
245 {
246 name = acquireConstraintName("U", i + 1);
247 unique.setName(name);
248 }
249 }
250 }
251 catch (EngineException nameAlreadyInUse)
252 {
253 log.error(nameAlreadyInUse, nameAlreadyInUse);
254 }
255 }
256
257 /***
258 * Macro to a constraint name.
259 *
260 * @param nameType constraint type
261 * @param nbr unique number for this constraint type
262 * @return unique name for constraint
263 * @throws EngineException
264 */
265 private final String acquireConstraintName(String nameType, int nbr)
266 throws EngineException
267 {
268 List inputs = new ArrayList(4);
269 inputs.add(getDatabase());
270 inputs.add(getName());
271 inputs.add(nameType);
272 inputs.add(new Integer(nbr));
273 return NameFactory.generateName(NameFactory.CONSTRAINT_GENERATOR,
274 inputs);
275 }
276
277 /***
278 * Gets the value of base class for classes produced from this table.
279 *
280 * @return The base class for classes produced from this table.
281 */
282 public String getBaseClass()
283 {
284 if (isAlias() && baseClass == null)
285 {
286 return alias;
287 }
288 else if (baseClass == null)
289 {
290 return getDatabase().getBaseClass();
291 }
292 else
293 {
294 return baseClass;
295 }
296 }
297
298 /***
299 * Set the value of baseClass.
300 * @param v Value to assign to baseClass.
301 */
302 public void setBaseClass(String v)
303 {
304 this.baseClass = v;
305 }
306
307 /***
308 * Get the value of basePeer.
309 * @return value of basePeer.
310 */
311 public String getBasePeer()
312 {
313 if (isAlias() && basePeer == null)
314 {
315 return alias + "Peer";
316 }
317 else if (basePeer == null)
318 {
319 return getDatabase().getBasePeer();
320 }
321 else
322 {
323 return basePeer;
324 }
325 }
326
327 /***
328 * Set the value of basePeer.
329 * @param v Value to assign to basePeer.
330 */
331 public void setBasePeer(String v)
332 {
333 this.basePeer = v;
334 }
335
336 /***
337 * A utility function to create a new column from attrib and add it to this
338 * table.
339 *
340 * @param attrib xml attributes for the column to add
341 * @return the added column
342 */
343 public Column addColumn(Attributes attrib)
344 {
345 Column col = new Column();
346 col.setTable(this);
347 col.loadFromXML(attrib);
348 addColumn(col);
349 return col;
350 }
351
352 /***
353 * Adds a new column to the column list and set the
354 * parent table of the column to the current table
355 *
356 * @param col the column to add
357 */
358 public void addColumn(Column col)
359 {
360 col.setTable (this);
361 if (col.isInheritance())
362 {
363 inheritanceColumn = col;
364 }
365 columnList.add(col);
366 columnsByName.put(col.getName(), col);
367 columnsByJavaName.put(col.getJavaName(), col);
368 col.setPosition(columnList.size());
369 needsTransactionInPostgres |= col.requiresTransactionInPostgres();
370 }
371
372 /***
373 * A utility function to create a new foreign key
374 * from attrib and add it to this table.
375 *
376 * @param attrib the xml attributes
377 * @return the created ForeignKey
378 */
379 public ForeignKey addForeignKey(Attributes attrib)
380 {
381 ForeignKey fk = new ForeignKey();
382 fk.loadFromXML(attrib);
383 addForeignKey(fk);
384 return fk;
385 }
386
387 /***
388 * Gets the column that subclasses of the class representing this
389 * table can be produced from.
390 */
391 public Column getChildrenColumn()
392 {
393 return inheritanceColumn;
394 }
395
396 /***
397 * Get the objects that can be created from this table.
398 */
399 public List getChildrenNames()
400 {
401 if (inheritanceColumn == null
402 || !inheritanceColumn.isEnumeratedClasses())
403 {
404 return null;
405 }
406 List children = inheritanceColumn.getChildren();
407 List names = new ArrayList(children.size());
408 for (int i = 0; i < children.size(); i++)
409 {
410 names.add(((Inheritance) children.get(i)).getClassName());
411 }
412 return names;
413 }
414
415 /***
416 * Adds the foreign key from another table that refers to this table.
417 *
418 * @param fk A foreign key refering to this table
419 */
420 public void addReferrer(ForeignKey fk)
421 {
422 if (referrers == null)
423 {
424 referrers = new ArrayList(5);
425 }
426 referrers.add(fk);
427 }
428
429 /***
430 * Get list of references to this table.
431 *
432 * @return A list of references to this table
433 */
434 public List getReferrers()
435 {
436 return referrers;
437 }
438
439 /***
440 * Set whether this table contains a foreign PK
441 *
442 * @param b
443 */
444 public void setContainsForeignPK(boolean b)
445 {
446 containsForeignPK = b;
447 }
448
449 /***
450 * Determine if this table contains a foreign PK
451 */
452 public boolean getContainsForeignPK()
453 {
454 return containsForeignPK;
455 }
456
457 /***
458 * A list of tables referenced by foreign keys in this table
459 *
460 * @return A list of tables
461 */
462 public List getForeignTableNames()
463 {
464 if (foreignTableNames == null)
465 {
466 foreignTableNames = new ArrayList(1);
467 }
468 return foreignTableNames;
469 }
470
471 /***
472 * Adds a new FK to the FK list and set the
473 * parent table of the column to the current table
474 *
475 * @param fk A foreign key
476 */
477 public void addForeignKey(ForeignKey fk)
478 {
479 fk.setTable (this);
480 foreignKeys.add(fk);
481
482 if (foreignTableNames == null)
483 {
484 foreignTableNames = new ArrayList(5);
485 }
486 if (!foreignTableNames.contains(fk.getForeignTableName()))
487 {
488 foreignTableNames.add(fk.getForeignTableName());
489 }
490 }
491
492 /***
493 * Return true if the column requires a transaction in Postgres
494 */
495 public boolean requiresTransactionInPostgres()
496 {
497 return needsTransactionInPostgres;
498 }
499
500 /***
501 * A utility function to create a new id method parameter
502 * from attrib and add it to this table.
503 */
504 public IdMethodParameter addIdMethodParameter(Attributes attrib)
505 {
506 IdMethodParameter imp = new IdMethodParameter();
507 imp.loadFromXML(attrib);
508 addIdMethodParameter(imp);
509 return imp;
510 }
511
512
513 /***
514 * Adds a new ID method parameter to the list and sets the parent
515 * table of the column associated with the supplied parameter to this table.
516 *
517 * @param imp The column to add as an ID method parameter.
518 */
519 public void addIdMethodParameter(IdMethodParameter imp)
520 {
521 imp.setTable(this);
522 if (idMethodParameters == null)
523 {
524 idMethodParameters = new ArrayList(2);
525 }
526 idMethodParameters.add(imp);
527 }
528
529 /***
530 * Adds a new index to the index list and set the
531 * parent table of the column to the current table
532 */
533 public void addIndex(Index index)
534 {
535 index.setTable (this);
536 indices.add(index);
537 }
538
539 /***
540 * A utility function to create a new index
541 * from attrib and add it to this table.
542 */
543 public Index addIndex(Attributes attrib)
544 {
545 Index index = new Index();
546 index.loadFromXML(attrib);
547 addIndex(index);
548 return index;
549 }
550
551 /***
552 * Adds a new Unique to the Unique list and set the
553 * parent table of the column to the current table
554 */
555 public void addUnique(Unique unique)
556 {
557 unique.setTable(this);
558 unices.add(unique);
559 }
560
561 /***
562 * A utility function to create a new Unique
563 * from attrib and add it to this table.
564 *
565 * @param attrib the xml attributes
566 */
567 public Unique addUnique(Attributes attrib)
568 {
569 Unique unique = new Unique();
570 unique.loadFromXML(attrib);
571 addUnique(unique);
572 return unique;
573 }
574
575 /***
576 * Get the name of the Table
577 */
578 public String getName()
579 {
580 return name;
581 }
582
583 /***
584 * Set the name of the Table
585 */
586 public void setName(String newName)
587 {
588 name = newName;
589 }
590
591 /***
592 * Get the description for the Table
593 */
594 public String getDescription()
595 {
596 return description;
597 }
598
599 /***
600 * Set the description for the Table
601 *
602 * @param newDescription description for the Table
603 */
604 public void setDescription(String newDescription)
605 {
606 description = newDescription;
607 }
608
609 /***
610 * Get name to use in Java sources
611 */
612 public String getJavaName()
613 {
614 if (javaName == null)
615 {
616 List inputs = new ArrayList(2);
617 inputs.add(name);
618 inputs.add(javaNamingMethod);
619 try
620 {
621 javaName = NameFactory.generateName(NameFactory.JAVA_GENERATOR,
622 inputs);
623 }
624 catch (EngineException e)
625 {
626 log.error(e, e);
627 }
628 }
629 return javaName;
630 }
631
632 /***
633 * Set name to use in Java sources
634 */
635 public void setJavaName(String javaName)
636 {
637 this.javaName = javaName;
638 }
639
640 /***
641 * Get the method for generating pk's
642 */
643 public String getIdMethod()
644 {
645 if (idMethod == null)
646 {
647 return IDMethod.NO_ID_METHOD;
648 }
649 else
650 {
651 return idMethod;
652 }
653 }
654
655 /***
656 * Set the method for generating pk's
657 */
658 public void setIdMethod(String idMethod)
659 {
660 this.idMethod = idMethod;
661 }
662
663 /***
664 * Skip generating sql for this table (in the event it should
665 * not be created from scratch).
666 * @return value of skipSql.
667 */
668 public boolean isSkipSql()
669 {
670 return (skipSql || isAlias() || isForReferenceOnly());
671 }
672
673 /***
674 * Set whether this table should have its creation sql generated.
675 * @param v Value to assign to skipSql.
676 */
677 public void setSkipSql(boolean v)
678 {
679 this.skipSql = v;
680 }
681
682 /***
683 * JavaName of om object this entry references.
684 * @return value of external.
685 */
686 public String getAlias()
687 {
688 return alias;
689 }
690
691 /***
692 * Is this table specified in the schema or is there just
693 * a foreign key reference to it.
694 * @return value of external.
695 */
696 public boolean isAlias()
697 {
698 return (alias != null);
699 }
700
701 /***
702 * Set whether this table specified in the schema or is there just
703 * a foreign key reference to it.
704 * @param v Value to assign to alias.
705 */
706 public void setAlias(String v)
707 {
708 this.alias = v;
709 }
710
711
712 /***
713 * Interface which objects for this table will implement
714 * @return value of interface.
715 */
716 public String getInterface()
717 {
718 return enterface;
719 }
720
721 /***
722 * Interface which objects for this table will implement
723 * @param v Value to assign to interface.
724 */
725 public void setInterface(String v)
726 {
727 this.enterface = v;
728 }
729
730 /***
731 * When a table is abstract, it marks the business object class that is
732 * generated as being abstract. If you have a table called "FOO", then the
733 * Foo BO will be <code>public abstract class Foo</code>
734 * This helps support class hierarchies
735 *
736 * @return value of abstractValue.
737 */
738 public boolean isAbstract()
739 {
740 return abstractValue;
741 }
742
743 /***
744 * When a table is abstract, it marks the business object
745 * class that is generated as being abstract. If you have a
746 * table called "FOO", then the Foo BO will be
747 * <code>public abstract class Foo</code>
748 * This helps support class hierarchies
749 *
750 * @param v Value to assign to abstractValue.
751 */
752 public void setAbstract(boolean v)
753 {
754 this.abstractValue = v;
755 }
756
757 /***
758 * Get the value of package.
759 *
760 * @return value of package.
761 */
762 public String getPackage()
763 {
764 if (pkg != null)
765 {
766 return pkg;
767 }
768 else
769 {
770 return this.getDatabase().getPackage();
771 }
772 }
773
774 /***
775 * Set the value of package.
776 *
777 * @param v Value to assign to package.
778 */
779 public void setPackage(String v)
780 {
781 this.pkg = v;
782 }
783
784 /***
785 * Returns a List containing all the columns in the table
786 *
787 * @return a List containing all the columns
788 */
789 public List getColumns()
790 {
791 return columnList;
792 }
793
794 /***
795 * Utility method to get the number of columns in this table
796 */
797 public int getNumColumns()
798 {
799 return columnList.size();
800 }
801
802 /***
803 * Returns a List containing all the FKs in the table
804 *
805 * @return a List containing all the FKs
806 */
807 public List getForeignKeys()
808 {
809 return foreignKeys;
810 }
811
812 /***
813 * Returns a Collection of parameters relevant for the chosen
814 * id generation method.
815 */
816 public List getIdMethodParameters()
817 {
818 return idMethodParameters;
819 }
820
821 /***
822 * A name to use for creating a sequence if one is not specified.
823 *
824 * @return name of the sequence
825 */
826 public String getSequenceName()
827 {
828 String result = null;
829 if (getIdMethod().equals(NATIVE))
830 {
831 List idMethodParams = getIdMethodParameters();
832 if (idMethodParams == null)
833 {
834 result = getName() + "_SEQ";
835 }
836 else
837 {
838 result = ((IdMethodParameter) idMethodParams.get(0)).getValue();
839 }
840 }
841 return result;
842 }
843
844 /***
845 * Returns a List containing all the indices in the table
846 *
847 * @return A List containing all the indices
848 */
849 public List getIndices()
850 {
851 return indices;
852 }
853
854 /***
855 * Returns a List containing all the UKs in the table
856 *
857 * @return A List containing all the UKs
858 */
859 public List getUnices()
860 {
861 return unices;
862 }
863
864 /***
865 * Returns a specified column.
866 *
867 * @param name name of the column
868 * @return Return a Column object or null if it does not exist.
869 */
870 public Column getColumn(String name)
871 {
872 return (Column) columnsByName.get(name);
873 }
874
875 /***
876 * Returns a specified column.
877 *
878 * @param javaName java name of the column
879 * @return Return a Column object or null if it does not exist.
880 */
881 public Column getColumnByJavaName(String javaName)
882 {
883 return (Column) columnsByJavaName.get(javaName);
884 }
885
886 /***
887 * Return the first foreign key that includes col in it's list
888 * of local columns. Eg. Foreign key (a,b,c) refrences tbl(x,y,z)
889 * will be returned of col is either a,b or c.
890 *
891 * @param col column name included in the key
892 * @return Return a Column object or null if it does not exist.
893 */
894 public ForeignKey getForeignKey(String col)
895 {
896 ForeignKey firstFK = null;
897 for (Iterator iter = foreignKeys.iterator(); iter.hasNext();)
898 {
899 ForeignKey key = (ForeignKey) iter.next();
900 if (key.getLocalColumns().contains(col))
901 {
902 if (firstFK == null)
903 {
904 firstFK = key;
905 }
906 else
907 {
908
909
910
911
912 }
913 }
914 }
915 return firstFK;
916 }
917
918 /***
919 * Returns true if the table contains a specified column
920 *
921 * @param col the column
922 * @return true if the table contains the column
923 */
924 public boolean containsColumn(Column col)
925 {
926 return columnList.contains(col);
927 }
928
929 /***
930 * Returns true if the table contains a specified column
931 *
932 * @param name name of the column
933 * @return true if the table contains the column
934 */
935 public boolean containsColumn(String name)
936 {
937 return (getColumn(name) != null);
938 }
939
940 /***
941 * Set the parent of the table
942 *
943 * @param parent the parant database
944 */
945 public void setDatabase(Database parent)
946 {
947 tableParent = parent;
948 }
949
950 /***
951 * Get the parent of the table
952 *
953 * @return the parant database
954 */
955 public Database getDatabase()
956 {
957 return tableParent;
958 }
959
960 /***
961 * Flag to determine if code/sql gets created for this table.
962 * Table will be skipped, if return true.
963 * @return value of forReferenceOnly.
964 */
965 public boolean isForReferenceOnly()
966 {
967 return forReferenceOnly;
968 }
969
970 /***
971 * Flag to determine if code/sql gets created for this table.
972 * Table will be skipped, if set to true.
973 * @param v Value to assign to forReferenceOnly.
974 */
975 public void setForReferenceOnly(boolean v)
976 {
977 this.forReferenceOnly = v;
978 }
979
980 /***
981 * Returns a XML representation of this table.
982 *
983 * @return XML representation of this table
984 */
985 public String toString()
986 {
987 StringBuffer result = new StringBuffer();
988
989 result.append ("<table name=\"")
990 .append(name)
991 .append('\"');
992
993 if (javaName != null)
994 {
995 result.append(" javaName=\"")
996 .append(javaName)
997 .append('\"');
998 }
999
1000 if (idMethod != null)
1001 {
1002 result.append(" idMethod=\"")
1003 .append(idMethod)
1004 .append('\"');
1005 }
1006
1007 if (skipSql)
1008 {
1009 result.append(" skipSql=\"")
1010 .append(new Boolean(skipSql))
1011 .append('\"');
1012 }
1013
1014 if (abstractValue)
1015 {
1016 result.append(" abstract=\"")
1017 .append(new Boolean(abstractValue))
1018 .append('\"');
1019 }
1020
1021 if (baseClass != null)
1022 {
1023 result.append(" baseClass=\"")
1024 .append(baseClass)
1025 .append('\"');
1026 }
1027
1028 if (basePeer != null)
1029 {
1030 result.append(" basePeer=\"")
1031 .append(basePeer)
1032 .append('\"');
1033 }
1034
1035 result.append(">\n");
1036
1037 if (columnList != null)
1038 {
1039 for (Iterator iter = columnList.iterator(); iter.hasNext();)
1040 {
1041 result.append(iter.next());
1042 }
1043 }
1044
1045 if (foreignKeys != null)
1046 {
1047 for (Iterator iter = foreignKeys.iterator(); iter.hasNext();)
1048 {
1049 result.append(iter.next());
1050 }
1051 }
1052
1053 if (idMethodParameters != null)
1054 {
1055 Iterator iter = idMethodParameters.iterator();
1056 while (iter.hasNext())
1057 {
1058 result.append(iter.next());
1059 }
1060 }
1061
1062 result.append ("</table>\n");
1063
1064 return result.toString();
1065 }
1066
1067 /***
1068 * Returns the collection of Columns which make up the single primary
1069 * key for this table.
1070 *
1071 * @return A list of the primary key parts.
1072 */
1073 public List getPrimaryKey()
1074 {
1075 List pk = new ArrayList(columnList.size());
1076
1077 Iterator iter = columnList.iterator();
1078 while (iter.hasNext())
1079 {
1080 Column col = (Column) iter.next();
1081 if (col.isPrimaryKey())
1082 {
1083 pk.add(col);
1084 }
1085 }
1086 return pk;
1087 }
1088
1089 /***
1090 * Determine whether this table has a primary key.
1091 *
1092 * @return Whether this table has any primary key parts.
1093 */
1094 public boolean hasPrimaryKey()
1095 {
1096 return (getPrimaryKey().size() > 0);
1097 }
1098
1099 /***
1100 * Returns all parts of the primary key, separated by commas.
1101 *
1102 * @return A CSV list of primary key parts.
1103 */
1104 public String printPrimaryKey()
1105 {
1106 return printList(columnList);
1107 }
1108
1109 /***
1110 * Returns the elements of the list, separated by commas.
1111 *
1112 * @param list a list of Columns
1113 * @return A CSV list.
1114 */
1115 private String printList(List list)
1116 {
1117 StringBuffer result = new StringBuffer();
1118 boolean comma = false;
1119 for (Iterator iter = list.iterator(); iter.hasNext();)
1120 {
1121 Column col = (Column) iter.next();
1122 if (col.isPrimaryKey())
1123 {
1124 if (comma)
1125 {
1126 result.append(',');
1127 }
1128 else
1129 {
1130 comma = true;
1131 }
1132 result.append(col.getName());
1133 }
1134 }
1135 return result.toString();
1136 }
1137 }