001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: package org.netbeans.modules.dbschema.jdbcimpl;
043:
044: import java.sql.*;
045: import java.util.*;
046:
047: import org.netbeans.modules.dbschema.*;
048: import org.netbeans.modules.dbschema.util.*;
049:
050: public class TableElementImpl extends DBElementImpl implements
051: TableElement.Impl {
052:
053: private DBElementsCollection columns;
054: private DBElementsCollection indexes;
055: private DBElementsCollection keys;
056: transient private DBElementsCollection columnPairs;
057:
058: private String table;
059:
060: private boolean isTable;
061:
062: public TableElementImpl() {
063: this (null);
064: }
065:
066: /** Creates new TableElementImpl */
067: public TableElementImpl(String table) {
068: super (table);
069: columns = new DBElementsCollection(this , new ColumnElement[0]);
070: //workaround for bug #4396371
071: //http://andorra.eng:8080/cgi-bin/ws.exe/bugtraq/bug.hts?where=bugid_value%3D4396371
072: Object hc = String.valueOf(columns.hashCode());
073: while (DBElementsCollection.instances.contains(hc)) {
074: columns = new DBElementsCollection(this ,
075: new ColumnElement[0]);
076: hc = String.valueOf(columns.hashCode());
077: }
078: DBElementsCollection.instances.add(hc);
079:
080: indexes = new DBElementsCollection(this , new IndexElement[0]);
081: //workaround for bug #4396371
082: //http://andorra.eng:8080/cgi-bin/ws.exe/bugtraq/bug.hts?where=bugid_value%3D4396371
083: hc = String.valueOf(indexes.hashCode());
084: while (DBElementsCollection.instances.contains(hc)) {
085: indexes = new DBElementsCollection(this ,
086: new IndexElement[0]);
087: hc = String.valueOf(indexes.hashCode());
088: }
089: DBElementsCollection.instances.add(hc);
090:
091: keys = new DBElementsCollection(this , new KeyElement[0]);
092: //workaround for bug #4396371
093: //http://andorra.eng:8080/cgi-bin/ws.exe/bugtraq/bug.hts?where=bugid_value%3D4396371
094: hc = String.valueOf(keys.hashCode());
095: while (DBElementsCollection.instances.contains(hc)) {
096: keys = new DBElementsCollection(this , new KeyElement[0]);
097: hc = String.valueOf(keys.hashCode());
098: }
099: DBElementsCollection.instances.add(hc);
100:
101: columnPairs = new DBElementsCollection(this ,
102: new ColumnPairElement[0]);
103: //workaround for bug #4396371
104: //http://andorra.eng:8080/cgi-bin/ws.exe/bugtraq/bug.hts?where=bugid_value%3D4396371
105: hc = String.valueOf(columnPairs.hashCode());
106: while (DBElementsCollection.instances.contains(hc)) {
107: columnPairs = new DBElementsCollection(this ,
108: new ColumnPairElement[0]);
109: hc = String.valueOf(columnPairs.hashCode());
110: }
111: DBElementsCollection.instances.add(hc);
112:
113: this .table = table;
114: }
115:
116: /** Get the name of this element.
117: * @return the name
118: */
119: public DBIdentifier getName() {
120: if (_name.getFullName() == null)
121: _name.setFullName(((TableElement) element)
122: .getDeclaringSchema().getName().getFullName()
123: + "." + _name.getName());
124:
125: return _name;
126: }
127:
128: /** Set whether this is really a table, or a view.
129: * @param isTable one of {@link #TABLE} or {@link #VIEW}
130: * @throws DBException if impossible
131: */
132: public void setTableOrView(boolean isTable) throws DBException {
133: this .isTable = isTable;
134: }
135:
136: /** Test whether this is really a class, or an interface.
137: * @return one of {@link #TABLE} or {@link #VIEW}
138: */
139: public boolean isTableOrView() {
140: return isTable;
141: }
142:
143: /** Change the set of columns.
144: * @param elems the columns to change
145: * @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET}
146: * @exception DBException if the action cannot be handled
147: */
148: public void changeColumns(ColumnElement[] elems, int action)
149: throws DBException {
150: columns.changeElements(elems, action);
151: }
152:
153: /** Get all columns.
154: * @return the columns
155: */
156: public ColumnElement[] getColumns() {
157: DBElement[] dbe = columns.getElements();
158: return (ColumnElement[]) Arrays.asList(dbe).toArray(
159: new ColumnElement[dbe.length]);
160: }
161:
162: /** Find a column by name.
163: * @param name the name for which to look
164: * @return the column, or <code>null</code> if it does not exist
165: */
166: public ColumnElement getColumn(DBIdentifier name) {
167: return (ColumnElement) columns.find(name);
168: }
169:
170: protected void initColumns(ConnectionProvider cp) {
171: if (cp != null)
172: try {
173: DatabaseMetaData dmd = cp.getDatabaseMetaData();
174: String shortTableName = getName().getName();
175:
176: DDLBridge bridge = null;
177: if (IDEUtil.isIDERunning())
178: bridge = new DDLBridge(cp.getConnection(), cp
179: .getSchema(), dmd);
180:
181: ResultSet rs;
182: if (bridge != null) {
183: bridge.getDriverSpecification().getColumns(
184: shortTableName, "%");
185: rs = bridge.getDriverSpecification().getResultSet();
186: } else
187: // rs = dmd.getColumns(cp.getConnection().getCatalog(), dmd.getUserName().trim(), shortTableName, "%");
188: rs = dmd.getColumns(
189: cp.getConnection().getCatalog(), cp
190: .getSchema(), shortTableName, "%");
191:
192: int sqlType;
193: String sqlTypeName;
194: String colName, colNull, colSize, colDec;
195: if (rs != null) {
196: HashMap rset = new HashMap();
197: while (rs.next()) {
198: if (bridge != null) {
199: rset = bridge.getDriverSpecification()
200: .getRow();
201: Object type = rset.get(new Integer(5));
202: if (type != null)
203: sqlType = (new Integer((String) rset
204: .get(new Integer(5))))
205: .intValue();
206: else
207: sqlType = 0; //java.sql.Types.NULL
208: sqlTypeName = (String) rset
209: .get(new Integer(6));
210: colName = (String) rset.get(new Integer(4));
211: colNull = (String) rset
212: .get(new Integer(11));
213: colSize = (String) rset.get(new Integer(7));
214: colDec = (String) rset.get(new Integer(9));
215: rset.clear();
216: } else {
217: sqlType = rs.getInt("DATA_TYPE"); //NOI18N
218: sqlTypeName = rs.getString("TYPE_NAME")
219: .trim(); //NOI18N
220: colName = rs.getString("COLUMN_NAME")
221: .trim(); //NOI18N
222: colNull = Integer.toString(rs
223: .getInt("NULLABLE")); //NOI18N
224: colSize = rs.getString("COLUMN_SIZE"); //NOI18N
225: colDec = rs.getString("DECIMAL_DIGITS"); //NOI18N
226: }
227:
228: String dbProductName = dmd
229: .getDatabaseProductName().trim();
230: //Oracle driver hacks
231: if (dbProductName.indexOf("Oracle") != -1) { //NOI18N
232: if (sqlType == 11
233: || ((sqlType == 1111) && sqlTypeName
234: .startsWith("TIMESTAMP")))
235: sqlType = Types.TIMESTAMP;
236: if ((sqlType == 1111)
237: && sqlTypeName.equals("FLOAT")) //NOI18N
238: sqlType = Types.DOUBLE;
239: if ((sqlType == 1111)
240: && sqlTypeName.equals("BLOB")) //NOI18N
241: sqlType = Types.BLOB;
242: if ((sqlType == 1111)
243: && sqlTypeName.equals("CLOB")) //NOI18N
244: sqlType = Types.CLOB;
245: if ((sqlType == 1111)
246: && sqlTypeName.equals("NVARCHAR2")) //NOI18N
247: sqlType = Types.CHAR;
248: }
249: //MySQL driver hacks
250: if (dbProductName.indexOf("MySQL") != -1) { //NOI18N
251: if ((sqlType == 1111)
252: && sqlTypeName
253: .equalsIgnoreCase("BIT")) //NOI18N
254: sqlType = Types.BIT;
255: }
256:
257: //workaround for i-net Oranxo driver
258: //value in int range is expected by JDBC API but 4294967296 is returned
259: try {
260: new Integer(colSize);
261: } catch (NumberFormatException exc) {
262: colSize = Integer
263: .toString(Integer.MAX_VALUE);
264: }
265:
266: ColumnElementImpl cei = new ColumnElementImpl(
267: colName, Integer.toString(sqlType),
268: colNull, colSize, colDec);
269: ColumnElement ce = new ColumnElement(cei,
270: (TableElement) element);
271: ColumnElement[] c = { ce };
272: changeColumns(c, DBElement.Impl.ADD);
273: }
274: rs.close();
275: }
276: } catch (Exception exc) {
277: if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
278: exc.printStackTrace();
279: }
280: }
281:
282: /** Change the set of indexes.
283: * @param elems the indexes to change
284: * @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET}
285: * @exception DBException if the action cannot be handled
286: */
287: public void changeIndexes(IndexElement[] elems, int action)
288: throws DBException {
289: indexes.changeElements(elems, action);
290: }
291:
292: /** Get all indexes.
293: * @return the indexes
294: */
295: public IndexElement[] getIndexes() {
296: DBElement[] dbe = indexes.getElements();
297: return (IndexElement[]) Arrays.asList(dbe).toArray(
298: new IndexElement[dbe.length]);
299: }
300:
301: /** Find an index by name.
302: * @param name the name for which to look
303: * @return the index, or <code>null</code> if it does not exist
304: */
305: public IndexElement getIndex(DBIdentifier name) {
306: return (IndexElement) indexes.find(name);
307: }
308:
309: protected void initIndexes(ConnectionProvider cp) {
310: initIndexes(cp, null);
311: }
312:
313: protected void initIndexes(ConnectionProvider cp, String tbl) {
314: if (cp != null)
315: try {
316: boolean unique;
317: DatabaseMetaData dmd = cp.getDatabaseMetaData();
318: String shortTableName;
319: if (tbl == null)
320: shortTableName = getName().getName();
321: else
322: shortTableName = tbl;
323:
324: DDLBridge bridge = null;
325: if (IDEUtil.isIDERunning())
326: bridge = new DDLBridge(cp.getConnection(), cp
327: .getSchema(), dmd);
328:
329: ResultSet rs;
330: if (bridge != null) {
331: bridge.getDriverSpecification().getIndexInfo(
332: shortTableName, false, true);
333: rs = bridge.getDriverSpecification().getResultSet();
334: } else
335: // rs = dmd.getIndexInfo(cp.getConnection().getCatalog(), dmd.getUserName().trim(), shortTableName, false, true);
336: rs = dmd.getIndexInfo(cp.getConnection()
337: .getCatalog(), cp.getSchema(),
338: shortTableName, false, true);
339:
340: String name, columnName;
341: boolean unq;
342: LinkedList idxs = new LinkedList();
343: if (rs != null) {
344: HashMap rset = new HashMap();
345: String uniqueStr;
346: while (rs.next()) {
347: if (bridge != null) {
348: rset = bridge.getDriverSpecification()
349: .getRow();
350: name = (String) rset.get(new Integer(6));
351: columnName = (String) rset.get(new Integer(
352: 9));
353: uniqueStr = (String) rset
354: .get(new Integer(4));
355: if (uniqueStr == null
356: || uniqueStr.equals("0")
357: || uniqueStr
358: .equalsIgnoreCase("false")
359: || uniqueStr.equalsIgnoreCase("f"))
360: unq = false;
361: else
362: unq = true;
363: rset.clear();
364: } else {
365: name = rs.getString("INDEX_NAME"); //NOI18N
366: columnName = rs.getString("COLUMN_NAME"); //NOI18N
367: if (columnName != null)
368: columnName = columnName.trim();
369: unq = rs.getBoolean("NON_UNIQUE"); //NOI18N
370: }
371: // hack for PostgreSQL bug 3480: the driver returns quotes around quoted column names
372: if (columnName != null
373: && columnName.length() >= 2
374: && columnName.startsWith("\"")
375: && columnName.endsWith("\"")) { // NOI18N
376: columnName = columnName.substring(1,
377: columnName.length() - 1);
378: }
379:
380: if (name == null)
381: continue;
382: else
383: name = name.trim();
384:
385: if (unq)
386: idxs
387: .add(name + "." + columnName
388: + ".false"); //NOI18N
389: else
390: idxs.add(name + "." + columnName + ".true"); //NOI18N
391: }
392: rs.close();
393: }
394:
395: String info;
396: int start, end;
397: for (int i = 0; i < idxs.size(); i++) {
398: info = idxs.get(i).toString();
399: start = info.indexOf('.'); //NOI18N
400: end = info.lastIndexOf('.'); //NOI18N
401: name = info.substring(0, start);
402: if ((info.substring(end + 1)).equals("true")) //NOI18N
403: unique = true;
404: else
405: unique = false;
406:
407: if (indexes.find(DBIdentifier.create(name)) != null)
408: continue;
409:
410: IndexElementImpl iei = new IndexElementImpl(this ,
411: name, unique);
412: IndexElement[] ie = { new IndexElement(iei,
413: (TableElement) element) };
414: iei.initColumns(idxs);
415: changeIndexes(ie, DBElement.Impl.ADD);
416: }
417: } catch (Exception exc) {
418: if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
419: exc.printStackTrace();
420: }
421: }
422:
423: /** Change the set of keys.
424: * @param elems the keys to change
425: * @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET}
426: * @exception DBException if the action cannot be handled
427: */
428: public void changeKeys(KeyElement[] elems, int action)
429: throws DBException {
430: keys.changeElements(elems, action);
431: }
432:
433: /** Get all keys.
434: * @return the keys
435: */
436: public KeyElement[] getKeys() {
437: DBElement[] dbe = keys.getElements();
438: return (KeyElement[]) Arrays.asList(dbe).toArray(
439: new KeyElement[dbe.length]);
440: }
441:
442: /** Find a key by name.
443: * @param name the name for which to look
444: * @return the key, or <code>null</code> if it does not exist
445: */
446: public KeyElement getKey(DBIdentifier name) {
447: return (KeyElement) keys.find(name);
448: }
449:
450: protected void initKeys(ConnectionProvider cp) {
451: initKeys(cp, 0);
452: }
453:
454: protected void initKeys(ConnectionProvider cp, int id) {
455: // id == 1 ... capture PK only
456: // id == 2 ... capture FKs only
457: initKeys(cp, id, null);
458: }
459:
460: protected void initKeys(ConnectionProvider cp, int id, String tbl) {
461: // id == 1 ... capture PK only
462: // id == 2 ... capture FKs only
463: // id == 3 ... capture FKs (and PKs), but don't expect that all related tables are provided. In other words,
464: // tries to initializes all FKs, but doesn't fail if some table is missing.
465:
466: if (cp != null)
467: try {
468: String shortTableName;
469: if (tbl == null)
470: shortTableName = getName().getName();
471: else
472: shortTableName = tbl;
473:
474: DDLBridge bridge = null;
475: if (IDEUtil.isIDERunning())
476: bridge = new DDLBridge(cp.getConnection(), cp
477: .getSchema(), cp.getDatabaseMetaData());
478:
479: boolean relatedTablesProvided = id != 3;
480: if (id != 1)
481: initFKs(cp, bridge, shortTableName,
482: relatedTablesProvided);
483: if (id != 2)
484: initPK(cp, bridge, shortTableName);
485: } catch (Exception exc) {
486: if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
487: exc.printStackTrace();
488: }
489: }
490:
491: /**
492: * @param expectRelatedTables specifies whether all related tables are expected to be provided.
493: */
494: private void initFKs(ConnectionProvider cp, DDLBridge bridge,
495: String shortTableName, boolean expectRelatedTables)
496: throws SQLException, DBException {
497: ResultSet rs;
498:
499: if (bridge != null) {
500: bridge.getDriverSpecification().getImportedKeys(
501: shortTableName);
502: rs = bridge.getDriverSpecification().getResultSet();
503: } else
504: rs = cp.getDatabaseMetaData().getImportedKeys(
505: cp.getConnection().getCatalog(), cp.getSchema(),
506: shortTableName);
507:
508: String name, fkColName, pkTableName, pkColName, c1, c2, s1, s2;
509: if (rs != null) {
510: HashMap rset = new HashMap();
511: while (rs.next()) {
512: if (bridge != null) {
513: rset = bridge.getDriverSpecification().getRow();
514:
515: //test references between two schemas
516: c1 = (String) rset.get(new Integer(1));
517: s1 = (String) rset.get(new Integer(2));
518: c2 = (String) rset.get(new Integer(5));
519: s2 = (String) rset.get(new Integer(6));
520:
521: name = (String) rset.get(new Integer(12));
522: fkColName = (String) rset.get(new Integer(8));
523: pkTableName = (String) rset.get(new Integer(3));
524: pkColName = (String) rset.get(new Integer(4));
525: rset.clear();
526: } else {
527: //test references between two schemas
528: c1 = rs.getString("PKTABLE_CAT"); //NOI18N
529: s1 = rs.getString("PKTABLE_SCHEM"); //NOI18N
530: c2 = rs.getString("FKTABLE_CAT"); //NOI18N
531: s2 = rs.getString("FKTABLE_SCHEM"); //NOI18N
532:
533: name = rs.getString("FK_NAME"); //NOI18N
534: fkColName = rs.getString("FKCOLUMN_NAME").trim(); //NOI18N
535: pkTableName = rs.getString("PKTABLE_NAME").trim(); //NOI18N
536: pkColName = rs.getString("PKCOLUMN_NAME").trim(); //NOI18N
537: }
538:
539: if (comp(c1, c2)) {
540: if (!comp(s1, s2))
541: continue;
542: } else
543: continue;
544:
545: ColumnPairElement cpe;
546:
547: if (name == null || name.trim().equals(""))
548: name = "GENERATED_FK_" + pkTableName;
549: else
550: name = name.trim();
551:
552: ColumnElement lce = getColumn(DBIdentifier
553: .create(fkColName)); //NOI18N
554: if (lce == null) //should be null only in same cases when FK is computed for view
555: continue;
556:
557: SchemaElement se = ((TableElement) element)
558: .getDeclaringSchema();
559: TableElement fte = se.getTable(DBIdentifier
560: .create(pkTableName));
561: // table could not be found since all related tables were not necessarily provided
562: if (fte == null && !expectRelatedTables) {
563: continue;
564: }
565: ColumnElement fce = fte.getColumn(DBIdentifier
566: .create(pkColName));
567: ColumnPairElementImpl cpei = new ColumnPairElementImpl(
568: lce.getName().getFullName() + ";"
569: + fce.getName().getFullName()); //NOI18N
570: cpe = new ColumnPairElement(cpei, lce, fce,
571: (TableElement) element);
572: changeColumnPairs(new ColumnPairElement[] { cpe },
573: DBElement.Impl.ADD);
574:
575: ForeignKeyElement fk = (ForeignKeyElement) keys
576: .find(DBIdentifier.create(name));
577: if (fk != null)
578: fk.addColumnPair(cpe); //add pair
579: else {
580: ForeignKeyElementImpl fkei = new ForeignKeyElementImpl(
581: this , name);
582: ForeignKeyElement fke = new ForeignKeyElement(fkei,
583: (TableElement) element);
584: fke.addColumnPair(cpe);
585: changeKeys(new ForeignKeyElement[] { fke },
586: DBElement.Impl.ADD);
587: }
588: }
589: rs.close();
590: }
591: }
592:
593: private void initPK(ConnectionProvider cp, DDLBridge bridge,
594: String shortTableName) throws SQLException, DBException {
595: ResultSet rs;
596:
597: IndexElement[] iearr = getIndexes();
598: if (iearr != null) {
599: for (int i = 0; i < iearr.length; i++)
600: if (iearr[i].isUnique()) {
601: UniqueKeyElementImpl ukei = new UniqueKeyElementImpl(
602: iearr[i].getName().getName(), false); //false = not primary key (primary flag is setted later)
603: UniqueKeyElement uke = new UniqueKeyElement(ukei,
604: (TableElement) element, iearr[i]);
605: uke.setColumns(iearr[i].getColumns());
606: changeKeys(new UniqueKeyElement[] { uke },
607: DBElement.Impl.ADD);
608: }
609:
610: UniqueKeyElement[] ukes = ((TableElement) element)
611: .getUniqueKeys();
612:
613: if (bridge != null) {
614: bridge.getDriverSpecification().getPrimaryKeys(
615: shortTableName);
616: rs = bridge.getDriverSpecification().getResultSet();
617: } else
618: rs = cp.getDatabaseMetaData().getPrimaryKeys(
619: cp.getConnection().getCatalog(),
620: cp.getSchema(), shortTableName);
621:
622: TreeMap cols = new TreeMap();
623: Object keySeq;
624: String colName;
625: if (rs != null) {
626: HashMap rset = new HashMap();
627: while (rs.next()) {
628: if (bridge != null) {
629: rset = bridge.getDriverSpecification().getRow();
630: keySeq = (Object) rset.get(new Integer(5));
631: colName = (String) rset.get(new Integer(4));
632: rset.clear();
633: } else {
634: keySeq = rs.getObject("KEY_SEQ"); //NOI18N
635: colName = rs.getString("COLUMN_NAME").trim(); //NOI18N
636: }
637:
638: cols.put(keySeq, colName); //NOI18N
639: }
640: rs.close();
641: }
642:
643: boolean primary = false;
644: if (cols != null && cols.size() > 0)
645: primary = true;
646:
647: if (primary) {
648: if (ukes == null || ukes.length == 0) {
649: // issue 56492: no index defined for the primary key
650: // generate a UniqueKeyElement and an IndexElement for it
651:
652: String indexName = "primary_key_index"; // NOI18N
653: int i = 1;
654: while (((TableElement) element)
655: .getIndex(DBIdentifier.create(indexName)) != null) {
656: indexName = indexName + i;
657: i++;
658: }
659:
660: LinkedList idxs = new LinkedList();
661: for (Iterator it = cols.values().iterator(); it
662: .hasNext();) {
663: // non-unique = false, thus the index is unique -- see initIndexes()
664: idxs
665: .add(indexName + "." + it.next()
666: + ".false"); // NOI18N
667: }
668:
669: IndexElementImpl iei = new IndexElementImpl(this ,
670: indexName, true);
671: IndexElement ie = new IndexElement(iei,
672: (TableElement) element);
673: iei.initColumns(idxs);
674: changeIndexes(new IndexElement[] { ie },
675: DBElement.Impl.ADD);
676:
677: UniqueKeyElementImpl ukei = new UniqueKeyElementImpl(
678: ie.getName().getName(), true);
679: UniqueKeyElement uke = new UniqueKeyElement(ukei,
680: (TableElement) element, ie);
681: uke.setColumns(ie.getColumns());
682: changeKeys(new UniqueKeyElement[] { uke },
683: DBElement.Impl.ADD);
684: } else if (ukes.length == 1)
685: ukes[0].setPrimaryKey(primary);
686: else {
687: ColumnElement[] ces;
688: Object[] o = cols.values().toArray();
689: boolean equals;
690: for (int i = 0; i < ukes.length; i++) {
691: ces = ukes[i].getColumns();
692: if (ces.length != o.length)
693: continue;
694: else {
695: equals = true;
696: for (int j = 0; j < ces.length; j++)
697: if (!o[j].toString().equals(
698: ces[j].getName().getName())) {
699: equals = false;
700: break;
701: }
702: if (equals) {
703: ukes[i].setPrimaryKey(primary);
704: break;
705: }
706: }
707: }
708: }
709: }
710: }
711: }
712:
713: public ColumnPairElement[] getColumnPairs() {
714: DBElement[] dbe = columnPairs.getElements();
715: return (ColumnPairElement[]) Arrays.asList(dbe).toArray(
716: new ColumnPairElement[dbe.length]);
717: }
718:
719: public ColumnPairElement getColumnPair(DBIdentifier name) {
720: ColumnPairElement cpe = (ColumnPairElement) columnPairs
721: .find(name);
722: if (cpe == null)
723: try {
724: String fullName = name.getFullName();
725: if (fullName == null) {
726: return null;
727: }
728:
729: int pos = fullName.indexOf(";");
730: String firstHalf = fullName.substring(0, pos);
731: String secondHalf = fullName.substring(pos + 1);
732:
733: ColumnElement lce = getColumn(DBIdentifier
734: .create(firstHalf));
735:
736: pos = secondHalf.lastIndexOf(".");
737: TableElement te = ((TableElement) element)
738: .getDeclaringSchema().getTable(
739: DBIdentifier.create(secondHalf
740: .substring(0, pos)));
741: if (te == null)
742: return null;
743:
744: ColumnElement fce = te.getColumn(DBIdentifier
745: .create(secondHalf));
746:
747: if (lce == null || fce == null)
748: return null;
749:
750: ColumnPairElementImpl cpei = new ColumnPairElementImpl(
751: lce.getName().getFullName() + ";"
752: + fce.getName().getFullName()); //NOI18N
753: cpe = new ColumnPairElement(cpei, lce, fce,
754: (TableElement) element);
755: changeColumnPairs(new ColumnPairElement[] { cpe },
756: DBElement.Impl.ADD);
757: } catch (DBException exc) {
758: exc.printStackTrace();
759: return null;
760: }
761:
762: return cpe;
763: }
764:
765: public void changeColumnPairs(ColumnPairElement[] pairs, int action)
766: throws DBException {
767: columnPairs.changeElements(pairs, action);
768: }
769:
770: //=============== extra methods needed for xml archiver ==============
771:
772: /** Returns the column collection of this table element. This method
773: * should only be used internally and for cloning and archiving.
774: * @return the column collection of this table element
775: */
776: public DBElementsCollection getColumnCollection() {
777: return columns;
778: }
779:
780: /** Set the column collection of this table element to the supplied
781: * collection. This method should only be used internally and for
782: * cloning and archiving.
783: * @param collection the column collection of this table element
784: */
785: public void setColumnCollection(DBElementsCollection collection) {
786: columns = collection;
787: }
788:
789: /** Returns the index collection of this table element. This method
790: * should only be used internally and for cloning and archiving.
791: * @return the index collection of this table element
792: */
793: public DBElementsCollection getIndexCollection() {
794: return indexes;
795: }
796:
797: /** Set the indwx collection of this table element to the supplied
798: * collection. This method should only be used internally and for
799: * cloning and archiving.
800: * @param collection the index collection of this table element
801: */
802: public void setIndexCollection(DBElementsCollection collection) {
803: indexes = collection;
804: }
805:
806: /** Returns the key collection of this table element. This method
807: * should only be used internally and for cloning and archiving.
808: * @return the key collection of this table element
809: */
810: public DBElementsCollection getKeyCollection() {
811: return keys;
812: }
813:
814: /** Set the key collection of this table element to the supplied
815: * collection. This method should only be used internally and for
816: * cloning and archiving.
817: * @param collection the key collection of this table element
818: */
819: public void setKeyCollection(DBElementsCollection collection) {
820: keys = collection;
821: }
822:
823: }
|