KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > versant > core > jdbc > sql > OracleSqlDriver


1
2 /*
3  * Copyright (c) 1998 - 2005 Versant Corporation
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License v1.0
6  * which accompanies this distribution, and is available at
7  * http://www.eclipse.org/legal/epl-v10.html
8  *
9  * Contributors:
10  * Versant Corporation - initial API and implementation
11  */

12 package com.versant.core.jdbc.sql;
13
14 import com.versant.core.jdbc.metadata.*;
15 import com.versant.core.jdbc.sql.conv.*;
16 import com.versant.core.jdbc.sql.diff.ColumnDiff;
17 import com.versant.core.jdbc.sql.diff.ControlParams;
18 import com.versant.core.jdbc.sql.diff.TableDiff;
19 import com.versant.core.jdbc.sql.exp.SqlExp;
20 import com.versant.core.util.CharBuf;
21 import com.versant.core.common.BindingSupportImpl;
22
23 import java.io.PrintWriter JavaDoc;
24 import java.sql.*;
25 import java.util.*;
26 import java.util.Date JavaDoc;
27
28 /**
29  * A driver for Oracle.
30  */

31 public class OracleSqlDriver extends SqlDriver {
32
33     protected CharacterStreamConverter.Factory characterStreamConverterFactory
34             = new CharacterStreamConverter.Factory();
35     protected InputStreamConverter.Factory inputStreamConverterFactory
36             = new InputStreamConverter.Factory();
37     protected OracleBlobConverter.Factory blobConverterFactory
38         = new OracleBlobConverter.Factory();
39     
40     protected OracleClobConverter.Factory clobConverterFactory
41             = new OracleClobConverter.Factory();
42     
43
44         
45     private HashMap typeDiffMap = null;
46
47     /**
48      * Get the name of this driver.
49      */

50     public String JavaDoc getName() {
51         return "oracle";
52     }
53
54     /**
55      * Get the default type mapping for the supplied JDBC type code from
56      * java.sql.Types or null if the type is not supported. There is no
57      * need to set the database or jdbcType on the mapping as this is done
58      * after this call returns. Subclasses should override this and to
59      * customize type mappings.
60      */

61     protected JdbcTypeMapping getTypeMapping(int jdbcType) {
62         switch (jdbcType) {
63             case Types.BIT:
64             case Types.TINYINT:
65                 return new JdbcTypeMapping("SMALLINT",
66                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.TRUE, null);
67             case Types.BIGINT:
68                 return new JdbcTypeMapping("NUMBER",
69                     19, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.TRUE, null);
70
71             case Types.DECIMAL:
72             
73             case Types.NUMERIC:
74                 return new JdbcTypeMapping("NUMBER",
75                     20, 10, JdbcTypeMapping.TRUE, JdbcTypeMapping.TRUE, null);
76             case Types.DATE:
77             case Types.TIME:
78             case Types.TIMESTAMP:
79                 return new JdbcTypeMapping("DATE",
80                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE, null);
81             case Types.DOUBLE:
82                 return new JdbcTypeMapping("DOUBLE PRECISION",
83                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE, null);
84             case Types.CLOB:
85                 return new JdbcTypeMapping("CLOB",
86                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE,
87                     clobConverterFactory);
88             case Types.LONGVARCHAR:
89                 return new JdbcTypeMapping("LONG",
90                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE,
91                     characterStreamConverterFactory);
92             case Types.VARCHAR:
93                 return new JdbcTypeMapping("VARCHAR2",
94                     255, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.TRUE, null);
95             case Types.LONGVARBINARY:
96                 return new JdbcTypeMapping("LONG RAW",
97                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE,
98                     inputStreamConverterFactory);
99
100             case Types.VARBINARY:
101             case Types.BLOB:
102                 return new JdbcTypeMapping("BLOB",
103                     0, 0, JdbcTypeMapping.TRUE, JdbcTypeMapping.FALSE,
104                     blobConverterFactory);
105
106                     
107         }
108         return super.getTypeMapping(jdbcType);
109     }
110
111     /**
112      * Get the default field mappings for this driver. These map java classes
113      * to column properties. Subclasses should override this, call super() and
114      * replace mappings as needed.
115      */

116     public HashMap getJavaTypeMappings() {
117         HashMap ans = super.getJavaTypeMappings();
118
119         BooleanConverter.Factory bcf = new BooleanConverter.Factory();
120         ((JdbcJavaTypeMapping)ans.get(Boolean.TYPE)).setConverterFactory(bcf);
121         ((JdbcJavaTypeMapping)ans.get(Boolean JavaDoc.class)).setConverterFactory(bcf);
122
123         DateTimestampConverter.Factory dtcf = new DateTimestampConverter.Factory();
124         ((JdbcJavaTypeMapping)ans.get(Date JavaDoc.class)).setConverterFactory(dtcf);
125
126
127
128         return ans;
129     }
130
131
132
133     /**
134      * Does the JDBC driver support statement batching?
135      */

136     public boolean isInsertBatchingSupported() {
137         return true;
138     }
139
140     /**
141      * Can batching be used if the statement contains a column with the
142      * given JDBC type?
143      */

144     public boolean isBatchingSupportedForJdbcType(int jdbcType) {
145         return jdbcType != Types.LONGVARCHAR
146             && jdbcType != Types.LONGVARBINARY;
147     }
148
149     /**
150      * Does the JDBC driver support statement batching for updates?
151      */

152     public boolean isUpdateBatchingSupported() {
153         return false;
154     }
155
156     /**
157      * Does the JDBC driver support scrollable result sets?
158      */

159     public boolean isScrollableResultSetSupported() {
160         return true;
161     }
162
163     /**
164      * Should indexes be used for columns in the order by list that are
165      * also in the select list? This is used for databases that will not
166      * order by a column that is duplicated in the select list (e.g. Oracle).
167      */

168     public boolean isUseIndexesForOrderCols() {
169         return true;
170     }
171
172     /**
173      * Is null a valid value for a column with a foreign key constraint?
174      */

175     public boolean isNullForeignKeyOk() {
176         return true;
177     }
178
179     /**
180      * How many PreparedStatement's should the pool be limited to by default
181      * (0 for unlimited) ?
182      */

183     public int getDefaultPsCacheMax() {
184         return 30;
185     }
186
187     /**
188      * Can 'SELECT FOR UPDATE' be used with a DISTINCT?
189      */

190     public boolean isSelectForUpdateWithDistinctOk() {
191         return false;
192     }
193
194     /**
195      * Create a default name generator instance for JdbcStore's using this
196      * driver.
197      */

198     public JdbcNameGenerator createJdbcNameGenerator() {
199         DefaultJdbcNameGenerator n = createDefaultJdbcNameGenerator();
200         n.setMaxColumnNameLength(30);
201         n.setMaxTableNameLength(30);
202         n.setMaxConstraintNameLength(30);
203         n.setMaxIndexNameLength(30);
204         return n;
205     }
206
207     /**
208      * Drop the table and all its constraints etc. This must remove
209      * constraints to this table from other tables so it can be dropped.
210      */

211     public void dropTable(Connection con, String JavaDoc table, Statement stat) throws SQLException {
212         stat.execute("DROP TABLE " + table + " CASCADE CONSTRAINTS");
213     }
214
215     /**
216      * Append the allow nulls part of the definition for a column in a
217      * create table statement.
218      */

219     protected void appendCreateColumnNulls(JdbcTable t, JdbcColumn c,
220             CharBuf s) {
221         if (!c.nulls) {
222             s.append(" NOT NULL");
223         } else {
224             s.append(" NULL");
225         }
226     }
227
228
229     /**
230      * Add the primary key constraint part of a create table statement to s.
231      */

232     protected void appendPrimaryKeyConstraint(JdbcTable t, CharBuf s) {
233         s.append("CONSTRAINT ");
234         s.append(t.pkConstraintName);
235         s.append(" PRIMARY KEY (");
236         appendColumnNameList(t.pk, s);
237         s.append(')');
238     }
239
240     /**
241      * Append an 'add constraint' statement for c.
242      */

243     protected void appendRefConstraint(CharBuf s, JdbcConstraint c) {
244         s.append("ALTER TABLE ");
245         s.append(c.src.name);
246         s.append(" ADD CONSTRAINT ");
247         s.append(c.name);
248         s.append(" FOREIGN KEY (");
249         appendColumnNameList(c.srcCols, s);
250         s.append(") REFERENCES ");
251         s.append(c.dest.name);
252         s.append('(');
253         appendColumnNameList(c.dest.pk, s);
254         s.append(')');
255     }
256
257     /**
258      * Append an 'drop constraint' statement for c.
259      */

260     protected void dropRefConstraint(CharBuf s, JdbcConstraint c) {
261         s.append("ALTER TABLE ");
262         s.append(c.src.name);
263         s.append(" DROP CONSTRAINT ");
264         s.append(c.name);
265     }
266
267     /**
268      * Write an SQL statement to a script with appropriate separator.
269      */

270     protected void print(PrintWriter JavaDoc out, String JavaDoc sql) {
271         out.print(sql);
272         out.println(";");
273         out.println();
274     }
275
276     /**
277      * Append the from list entry for a table that is the right hand table
278      * in a join i.e. it is being joined to.
279      * @param exp This is the expression that joins the tables
280      * @param outer If true then this is an outer join
281      */

282     public void appendSqlFromJoin(JdbcTable table, String JavaDoc alias, SqlExp exp,
283             boolean outer, CharBuf s) {
284         s.append(',');
285         s.append(' ');
286         s.append(table.name);
287         if (alias != null) {
288             s.append(' ');
289             s.append(alias);
290         }
291     }
292
293     /**
294      * Append a join expression.
295      */

296     public void appendSqlJoin(String JavaDoc leftAlias, JdbcColumn left,
297             String JavaDoc rightAlias, JdbcColumn right, boolean outer,
298             CharBuf s) {
299         s.append(leftAlias);
300         s.append('.');
301         s.append(left.name);
302         s.append(' ');
303         s.append('=');
304         s.append(' ');
305         s.append(rightAlias);
306         s.append('.');
307         s.append(right.name);
308         if (outer) {
309             s.append(' ');
310             s.append('(');
311             s.append('+');
312             s.append(')');
313         }
314     }
315
316     /**
317      * Get default SQL to test a connection or null if none available. This
318      * must be a query that returns at least one row.
319      */

320     public String JavaDoc getConnectionValidateSQL() {
321         return "SELECT sysdate FROM dual";
322     }
323
324     /**
325      * Gets the current user's schema
326      */

327     protected String JavaDoc getSchema(Connection con) {
328         String JavaDoc schema = null;
329         String JavaDoc sql = "SELECT sys_context('USERENV','CURRENT_SCHEMA') FROM dual";
330         try {
331             Statement statement = con.createStatement();
332             ResultSet rs = statement.executeQuery(sql);
333             if (rs.next()){
334                 schema = rs.getString(1);
335             }
336             try {
337                 statement.close();
338             } catch (SQLException e) {
339             }
340         } catch (SQLException sqle) {
341             //hide
342
}
343         return schema;
344     }
345
346     /**
347      * Get con ready for a getQueryPlan call. Example: On Sybase this will
348      * do a 'set showplan 1' and 'set noexec 1'. Also make whatever changes
349      * are necessary to sql to prepare it for a getQueryPlan call. Example:
350      * On Oracle this will prepend 'explain '. The cleanupForGetQueryPlan
351      * method must be called in a finally block if this method is called.
352      * @see #cleanupForGetQueryPlan
353      * @see #getQueryPlan
354      */

355     public String JavaDoc prepareForGetQueryPlan(Connection con, String JavaDoc sql) {
356         try{
357             createPlan(con);
358         } catch (SQLException sqle){
359             sqle.printStackTrace();
360         }
361         return "EXPLAIN PLAN SET statement_id = 'JDO_PLAN' INTO jdo_plan_table FOR "+sql;
362     }
363
364     private void createPlan(Connection con) throws SQLException{
365         String JavaDoc exists ="SELECT TABLE_NAME FROM SYS.ALL_TABLES WHERE table_name = 'JDO_PLAN_TABLE'";
366         Statement existsStat = con.createStatement();
367         ResultSet rs = existsStat.executeQuery(exists);
368         if (rs.next()){
369             try{
370                 rs.close();
371                 existsStat.close();
372             } catch (SQLException e){ }
373
374         } else {
375             Statement statement = con.createStatement();
376             String JavaDoc create =
377                     "CREATE TABLE jdo_plan_table (" +
378                     " STATEMENT_ID VARCHAR2(30)," +
379                     " TIMESTAMP DATE," +
380                     " REMARKS VARCHAR2(80)," +
381                     " OPERATION VARCHAR2(30)," +
382                     " OPTIONS VARCHAR2(30)," +
383                     " OBJECT_NODE VARCHAR2(128)," +
384                     " OBJECT_OWNER VARCHAR2(30)," +
385                     " OBJECT_NAME VARCHAR2(30)," +
386                     " OBJECT_INSTANCE NUMBER(38)," +
387                     " OBJECT_TYPE VARCHAR2(30)," +
388                     " OPTIMIZER VARCHAR2(255)," +
389                     " SEARCH_COLUMNS NUMBER," +
390                     " ID NUMBER(38)," +
391                     " PARENT_ID NUMBER(38)," +
392                     " POSITION NUMBER(38)," +
393                     " COST NUMBER(38)," +
394                     " CARDINALITY NUMBER(38)," +
395                     " BYTES NUMBER(38)," +
396                     " OTHER_TAG VARCHAR2(255)," +
397                     " PARTITION_START VARCHAR2(255)," +
398                     " PARTITION_STOP VARCHAR2(255)," +
399                     " PARTITION_ID NUMBER(38)," +
400                     " OTHER LONG," +
401                     " DISTRIBUTION VARCHAR2(30) )";
402
403             statement.execute(create);
404
405             try{
406                 rs.close();
407                 existsStat.close();
408                 statement.close();
409             } catch (SQLException e){ }
410
411         }
412     }
413
414     /**
415      * Get the query plan for ps and cleanup anything done in
416      * prepareForGetQueryPlan. Return null if this is not supported.
417      * @see #prepareForGetQueryPlan
418      * @see #cleanupForGetQueryPlan
419      */

420     public String JavaDoc getQueryPlan(Connection con, PreparedStatement ps) {
421         StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
422         Statement stat = null;
423         ResultSet rs = null;
424         try{
425
426             ps.execute();
427
428             stat = con.createStatement();
429
430
431             String JavaDoc select =
432                     "select lpad(' ',4*(level-1))||operation||' ('||options||') '|| object_name||' ' "+
433                     " ||decode(object_type,'','','('||object_type||') ') "+
434                     " ||decode(object_node,'','','['||object_node||'] ') "+
435                     " ||decode(OPTIMIZER,'','','['||OPTIMIZER||'] ') "+
436                     " ||decode(id,0,'Cost='||position, "+
437                     " decode(COST,'','',' Cost='||COST||' ' "+
438                     " ||decode(id,0,'','Card='||CARDINALITY||' ') "+
439                     " ||decode(id,0,'','Bytes='||BYTES) "+
440                     " ) ) query "+
441                     "from jdo_plan_table "+
442                     " where statement_id = 'JDO_PLAN' "+
443                     "start with id = 0 "+
444                     "connect by prior id = parent_id "+
445                     "ORDER BY id";
446             rs = stat.executeQuery(select);
447
448             int count = -1;
449             while (rs != null && rs.next()) {
450                 if (count == -1){
451                     count = 0;
452                 } else {
453                     buff.append('\n');
454                 }
455                 buff.append(rs.getString(1));
456             }
457         } catch (Exception JavaDoc sqle){
458             sqle.printStackTrace();
459         } finally {
460             try{
461                 rs.close();
462                 stat.close();
463             } catch (Exception JavaDoc e){}
464         }
465         return buff.toString();
466     }
467
468     /**
469      * Cleanup anything done in prepareForGetQueryPlan. Example: On Sybase this
470      * will do a 'set showplan 0' and 'set noexec 0'.
471      * @see #prepareForGetQueryPlan
472      * @see #getQueryPlan
473      */

474     public void cleanupForGetQueryPlan(Connection con) {
475         try{
476             Statement statement2 = con.createStatement();
477             statement2.execute("DROP TABLE jdo_plan_table");
478             try{
479                 statement2.close();
480             } catch (SQLException e){}
481         } catch (SQLException sqle){
482             sqle.printStackTrace();
483         }
484     }
485
486     /**
487      * Get the JdbcTables from the database for the given database con.
488      * @param con
489      * @return HashMap of tablename.toLowerCase() as key and JdbcTable as value
490      * @throws SQLException on DB errors
491      */

492     public HashMap getDBSchema(Connection con, ControlParams params) throws SQLException {
493         HashMap jdbcTableMap = new HashMap(); // main map of jdbc tables
494

495         HashMap synonymMap = new HashMap();
496         try {
497             String JavaDoc synonymSql =
498                     "SELECT TABLE_NAME,\n" +
499                     " SYNONYM_NAME \n" +
500                     " FROM ALL_SYNONYMS \n" +
501                     " WHERE SYNONYM_NAME NOT LIKE TABLE_NAME ";
502             Statement statSynonym = con.createStatement();
503             ResultSet rsSynonym = statSynonym.executeQuery(synonymSql);
504             while (rsSynonym.next()) {
505                 synonymMap.put(rsSynonym.getString(1).toLowerCase(), rsSynonym.getString(2).toLowerCase());
506             }
507             // clean up
508
if (rsSynonym != null) {
509                 try {
510                     rsSynonym.close();
511                 } catch (SQLException e) { }
512             }
513             if (statSynonym != null) {
514                 try {
515                     statSynonym.close();
516                 } catch (SQLException e) { }
517             }
518         } catch (SQLException e) {
519             // hide all
520
}
521
522         // now we do columns
523
String JavaDoc tableName = null;
524
525         String JavaDoc columnSql =
526                 "SELECT DISTINCT t.table_name AS table_name,\n" +
527                 " t.column_name AS column_name,\n" +
528                 " DECODE (t.data_type, 'CHAR', 1,'NCHAR', 1,'NVARCHAR2', 12, 'VARCHAR2', 12,\n" +
529                 " 'NUMBER', 3, 'LONG', -1, 'DATE', 91, 'RAW', -3, 'LONG RAW', -4,\n" +
530                 " 'FLOAT', DECODE (DECODE (t.data_precision, null, t.data_length, t.data_precision),126,8,6),\n" +
531                 " 'BLOB', 2004,'BFILE', 2004,'CLOB',2005,'NCLOB', 2005, 'TIMESTAMP(6)', 93,'TIMESTAMP', 93, \n" +
532                 " 'TIMESTAMP WITH LOCAL TIME ZONE' , 93 ,'TIMESTAMP WITH TIME ZONE',12,\n" +
533                 " 'XMLTYPE',2005, 1111) AS data_type, \n" +
534                 " t.data_type AS type_name,\n" +
535                 " decode(t.data_type, 'CLOB', 2147483647, 'NCLOB', 2147483647, 'LONG', 2147483647,\n" +
536                 " 'BLOB', 2147483647, 'LONG RAW', 2147483647, 'BFILE', 2147483647, 'DATE', 19,\n" +
537                 " 'ROWID', 18, DECODE (t.data_precision, null, t.data_length, t.data_precision)) as column_size,\n" +
538                 " t.data_scale AS decimal_digits,\n" +
539                 " DECODE (t.nullable, 'N', 0, 1) AS nullable,\n" +
540                 " t.column_id AS ordinal_position\n" +
541                 " FROM user_tab_columns t,\n" +
542                 " user_tables u\n" +
543                 " WHERE u.table_name = t.table_name\n" +
544                 " AND u.table_name NOT LIKE('AQ$_%')\n" +
545                 " AND u.table_name NOT LIKE('DEF$_%')\n" +
546                 " AND u.table_name NOT LIKE('LOGMNR_%')\n" +
547                 " AND u.table_name NOT LIKE('LOGSTDBY$%')\n" +
548                 " AND u.table_name NOT LIKE('MVIEW$_%')\n" +
549                 " AND u.table_name NOT LIKE('REPCAT$_%')\n" +
550                 " AND u.table_name NOT LIKE('SQLPLUS_PRODUCT_PROFILE')\n" +
551                 " AND u.table_name NOT LIKE('HELP')\n" +
552                 " ORDER BY table_name, ordinal_position ";
553         Statement statCol = con.createStatement();
554         ResultSet rsColumn = statCol.executeQuery(columnSql);
555         ArrayList columns = null;
556
557         while (rsColumn.next()) {
558
559             String JavaDoc temptableName = rsColumn.getString(1);
560
561             if (tableName == null) { // this is the first one
562
tableName = temptableName;
563                 columns = new ArrayList();
564                 JdbcTable jdbcTable = new JdbcTable();
565                 jdbcTable.name = tableName;
566                 jdbcTableMap.put(tableName, jdbcTable);
567             }
568
569             if (!temptableName.equals(tableName)) { // now we set everyting up for prev table
570
JdbcColumn[] jdbcColumns = new JdbcColumn[columns.size()];
571                 columns.toArray(jdbcColumns);
572                 JdbcTable jdbcTable0 = (JdbcTable) jdbcTableMap.get(tableName);
573                 jdbcTable0.cols = jdbcColumns;
574
575
576                 tableName = temptableName;
577                 columns.clear();
578                 JdbcTable jdbcTable1 = new JdbcTable();
579                 jdbcTable1.name = tableName;
580                 jdbcTableMap.put(tableName, jdbcTable1);
581             }
582
583             JdbcColumn col = new JdbcColumn();
584
585             col.name = rsColumn.getString(2);
586             col.sqlType = rsColumn.getString(4);
587             col.jdbcType = rsColumn.getInt(3);
588             col.length = rsColumn.getInt(5);
589             col.scale = rsColumn.getInt(6);
590 // if (col.sqlType.equals("NUMBER") &&
591
// col.jdbcType == 3
592
// && col.scale == 0){
593
// col.jdbcType = java.sql.Types.INTEGER;
594
// }
595
col.nulls = rsColumn.getBoolean(7);
596
597             switch (col.jdbcType) {
598                 case java.sql.Types.DATE:
599                 case java.sql.Types.TIME:
600                 case java.sql.Types.TIMESTAMP:
601                     col.length = 0;
602                     col.scale = 0;
603                 default:
604             }
605             columns.add(col);
606         }
607         // we fin last table
608
if (columns != null){
609             JdbcColumn[] jdbcColumns = new JdbcColumn[columns.size()];
610             columns.toArray(jdbcColumns);
611             JdbcTable colJdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
612             if (colJdbcTable != null){
613                 colJdbcTable.cols = jdbcColumns;
614             }
615             columns.clear();
616         }
617         tableName = null;
618
619         // clean up
620
if (rsColumn != null) {
621             try {
622                 rsColumn.close();
623             } catch (SQLException e) {
624             }
625         }
626         if (statCol != null) {
627             try {
628                 statCol.close();
629             } catch (SQLException e) {
630             }
631         }
632         if (!params.checkColumnsOnly()) {
633             if (params.isCheckPK()) {
634                 // now we do primaryKeys
635
HashMap pkMap = null;
636
637                 String JavaDoc pkSql =
638                         "SELECT c.table_name,\n" +
639                         " c.column_name,\n" +
640                         " c.position ,\n" +
641                         " c.constraint_name \n" +
642                         "FROM user_cons_columns c,\n" +
643                         " user_constraints k\n" +
644                         "WHERE k.constraint_type = 'P'\n" +
645                         " AND k.constraint_name = c.constraint_name\n" +
646                         " AND k.table_name = c.table_name \n" +
647                         " AND k.table_name NOT LIKE('AQ$_%')\n" +
648                         " AND k.table_name NOT LIKE('DEF$_%')\n" +
649                         " AND k.table_name NOT LIKE('LOGMNR_%')\n" +
650                         " AND k.table_name NOT LIKE('LOGSTDBY$%')\n" +
651                         " AND k.table_name NOT LIKE('MVIEW$_%')\n" +
652                         " AND k.table_name NOT LIKE('REPCAT$_%')\n" +
653                         " AND k.table_name NOT LIKE('SQLPLUS_PRODUCT_PROFILE')\n" +
654                         " AND k.table_name NOT LIKE('HELP')\n" +
655                         " AND k.owner = c.owner \n" +
656                         "ORDER BY c.table_name,c.constraint_name,c.position";
657
658                 Statement statPK = con.createStatement();
659                 ResultSet rsPKs = statPK.executeQuery(pkSql);
660                 int pkCount = 0;
661                 String JavaDoc pkName = null;
662                 while (rsPKs.next()) {
663                     String JavaDoc temptableName = rsPKs.getString(1);
664
665                     if (!jdbcTableMap.containsKey(temptableName)) {
666                         continue;
667                     }
668
669                     if (tableName == null) { // this is the first one
670
tableName = temptableName;
671                         pkMap = new HashMap();
672                     }
673
674                     if (!temptableName.equals(tableName)) { // now we set everyting up for prev table
675
JdbcColumn[] pkColumns = new JdbcColumn[pkCount];
676                         int indexOfPKCount = 0;
677                         JdbcTable jdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
678                         for (int i = 0; i < jdbcTable.cols.length; i++) {
679                             JdbcColumn jdbcColumn = jdbcTable.cols[i];
680                             if (pkMap.containsKey(jdbcColumn.name)) {
681                                 pkColumns[indexOfPKCount] = jdbcColumn;
682                                 jdbcColumn.pk = true;
683                                 indexOfPKCount++;
684                             }
685                         }
686                         jdbcTable.pk = pkColumns;
687                         jdbcTable.pkConstraintName = pkName;
688
689
690                         tableName = temptableName;
691                         pkMap.clear();
692                         pkCount = 0;
693                     }
694                     pkCount++;
695                     pkMap.put(rsPKs.getString(2), null);
696                     pkName = rsPKs.getString(4);
697                 }
698                 JdbcColumn[] pkColumns = new JdbcColumn[pkCount];
699                 int indexOfPKCount = 0;
700                 JdbcTable pkJdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
701                 if (pkJdbcTable != null) {
702                     for (int i = 0; i < pkJdbcTable.cols.length; i++) {
703                         JdbcColumn jdbcColumn = pkJdbcTable.cols[i];
704                         if (pkMap.containsKey(jdbcColumn.name)) {
705                             pkColumns[indexOfPKCount] = jdbcColumn;
706                             jdbcColumn.pk = true;
707                             indexOfPKCount++;
708                         }
709                     }
710                     pkJdbcTable.pk = pkColumns;
711                     pkJdbcTable.pkConstraintName = pkName;
712                 }
713                 tableName = null;
714                 // clean up
715
if (rsPKs != null) {
716                     try {
717                         rsPKs.close();
718                     } catch (SQLException e) {
719                     }
720                 }
721                 if (statPK != null) {
722                     try {
723                         statPK.close();
724                     } catch (SQLException e) {
725                     }
726                 }
727             }
728             if (params.isCheckIndex()) {
729                 // now we do index
730
String JavaDoc indexSql =
731                         "select i.table_name,\n" +
732                         " c.column_name,\n" +
733                         " i.index_name,\n" +
734                         " decode (i.uniqueness, 'UNIQUE', 0, 1) as NON_UNIQUE,\n" +
735                         " 1 as type,\n" +
736                         " c.column_position as ordinal_position\n" +
737                         " from user_indexes i,\n" +
738                         " user_ind_columns c \n" +
739                         " where i.index_name = c.index_name\n" +
740                         " AND i.table_name = c.table_name\n" +
741                         " AND i.table_name NOT LIKE('AQ$_%')\n" +
742                         " AND i.table_name NOT LIKE('DEF$_%')\n" +
743                         " AND i.table_name NOT LIKE('LOGMNR_%')\n" +
744                         " AND i.table_name NOT LIKE('LOGSTDBY$%')\n" +
745                         " AND i.table_name NOT LIKE('MVIEW$_%')\n" +
746                         " AND i.table_name NOT LIKE('REPCAT$_%')\n" +
747                         " AND i.table_name NOT LIKE('SQLPLUS_PRODUCT_PROFILE')\n" +
748                         " AND i.table_name NOT LIKE('HELP')" +
749                         " order by i.table_name,index_name, ordinal_position";
750                 Statement statIndex = con.createStatement();
751                 ResultSet rsIndex = statIndex.executeQuery(indexSql);
752
753                 HashMap indexNameMap = null;
754                 ArrayList indexes = null;
755                 while (rsIndex.next()) {
756                     String JavaDoc temptableName = rsIndex.getString(1);
757                     if (tableName == null) { // this is the first one
758
tableName = temptableName;
759                         indexNameMap = new HashMap();
760                         indexes = new ArrayList();
761                     }
762
763                     String JavaDoc indexName = rsIndex.getString(3);
764                     JdbcTable tempJdbcTable = (JdbcTable) jdbcTableMap.get(temptableName);
765
766                     if (tempJdbcTable == null){
767                         continue;
768                     }
769
770                     if (indexName != null && !indexName.equals(tempJdbcTable.pkConstraintName)) {
771                         if (!temptableName.equals(tableName)) { // now we set everyting up for prev table
772
JdbcTable jdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
773                             JdbcIndex[] jdbcIndexes = new JdbcIndex[indexes.size()];
774                             indexes.toArray(jdbcIndexes);
775                             jdbcTable.indexes = jdbcIndexes;
776
777
778                             tableName = temptableName;
779                             indexes.clear();
780                             indexNameMap.clear();
781
782                         }
783                         JdbcTable jdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
784                         if (indexNameMap.containsKey(indexName)) {
785                             JdbcIndex index = null;
786                             for (Iterator iter = indexes.iterator(); iter.hasNext();) {
787                                 JdbcIndex jdbcIndex = (JdbcIndex) iter.next();
788                                 if (jdbcIndex.name.equals(indexName)) {
789                                     index = jdbcIndex;
790                                 }
791                             }
792
793                             JdbcColumn[] tempIndexColumns = index.cols;
794                             JdbcColumn[] indexColumns = new JdbcColumn[tempIndexColumns.length + 1];
795                             System.arraycopy(tempIndexColumns, 0, indexColumns, 0, tempIndexColumns.length);
796                             String JavaDoc colName = rsIndex.getString(2);
797                             boolean foundCol = false;
798                             for (int i = 0; i < jdbcTable.cols.length; i++) {
799                                 JdbcColumn jdbcColumn = jdbcTable.cols[i];
800                                 if (colName.equalsIgnoreCase(jdbcColumn.name)) {
801                                     indexColumns[tempIndexColumns.length] = jdbcColumn;
802                                     jdbcColumn.partOfIndex = true;
803                                     foundCol = true;
804                                 }
805                             }
806
807                             if (foundCol){
808                                 index.setCols(indexColumns);
809                             }
810                         } else {
811                             indexNameMap.put(indexName, null);
812                             JdbcIndex index = new JdbcIndex();
813                             index.name = indexName;
814                             index.unique = !rsIndex.getBoolean(4);
815                             short indexType = rsIndex.getShort(5);
816                             switch (indexType) {
817                                 case DatabaseMetaData.tableIndexClustered:
818                                     index.clustered = true;
819                                     break;
820                             }
821                             String JavaDoc colName = rsIndex.getString(2);
822                             JdbcColumn[] indexColumns = new JdbcColumn[1];
823                             boolean foundCol = false;
824                             for (int i = 0; i < jdbcTable.cols.length; i++) {
825                                 JdbcColumn jdbcColumn = jdbcTable.cols[i];
826                                 if (colName.equalsIgnoreCase(jdbcColumn.name)) {
827                                     indexColumns[0] = jdbcColumn;
828                                     jdbcColumn.partOfIndex = true;
829                                     foundCol = true;
830                                 }
831                             }
832                             if (foundCol) {
833                                 index.setCols(indexColumns);
834                                 indexes.add(index);
835                             }
836                         }
837                     }
838                 }
839                 JdbcTable indexJdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
840                 if (indexJdbcTable != null) {
841                     if (indexJdbcTable != null){
842                         JdbcIndex[] jdbcIndexes = new JdbcIndex[indexes.size()];
843                         indexes.toArray(jdbcIndexes);
844                         indexJdbcTable.indexes = jdbcIndexes;
845                     }
846                     indexes.clear();
847                     indexNameMap.clear();
848                 }
849                 tableName = null;
850                 // clean up
851
if (rsIndex != null){
852                     try {
853                         rsIndex.close();
854                     } catch (SQLException e) { }
855                 }
856                 if (statIndex != null) {
857                     try {
858                         statIndex.close();
859                     } catch (SQLException e) { }
860                 }
861             }
862             if (params.isCheckConstraint()) {
863                 // now we do forign keys
864

865                 String JavaDoc fkSql =
866                         "SELECT p.table_name as pktable_name,\n" +
867                         " pc.column_name as pkcolumn_name,\n" +
868                         " f.table_name as fktable_name,\n" +
869                         " fc.column_name as fkcolumn_name,\n" +
870                         " fc.position as key_seq,\n" +
871                         " f.constraint_name as fk_name,\n" +
872                         " p.constraint_name as pk_name\n" +
873                         "FROM user_cons_columns pc, \n" +
874                         " user_constraints p,\n" +
875                         " user_cons_columns fc,\n" +
876                         " user_constraints f\n" +
877                         "WHERE f.constraint_type = 'R'\n" +
878                         " AND p.owner = f.r_owner \n" +
879                         " AND p.constraint_name = f.r_constraint_name\n" +
880                         " AND p.constraint_type = 'P'\n" +
881                         " AND pc.owner = p.owner\n" +
882                         " AND pc.constraint_name = p.constraint_name\n" +
883                         " AND pc.table_name = p.table_name\n" +
884                         " AND fc.owner = f.owner\n" +
885                         " AND fc.constraint_name = f.constraint_name\n" +
886                         " AND fc.table_name = f.table_name\n" +
887                         " AND f.table_name NOT LIKE('AQ$_%')\n" +
888                         " AND f.table_name NOT LIKE('DEF$_%')\n" +
889                         " AND f.table_name NOT LIKE('LOGMNR_%')\n" +
890                         " AND f.table_name NOT LIKE('LOGSTDBY$%')\n" +
891                         " AND f.table_name NOT LIKE('MVIEW$_%')\n" +
892                         " AND f.table_name NOT LIKE('REPCAT$_%')\n" +
893                         " AND f.table_name NOT LIKE('SQLPLUS_PRODUCT_PROFILE')\n" +
894                         " AND f.table_name NOT LIKE('HELP')\n" +
895                         " AND fc.position = pc.position\n" +
896                         "ORDER BY fktable_name, fk_name,key_seq ";
897                 Statement statFK = con.createStatement();
898                 ResultSet rsFKs = statFK.executeQuery(fkSql);
899
900                 HashMap constraintNameMap = null;
901                 ArrayList constraints = null;
902                 while (rsFKs.next()) {
903                     String JavaDoc temptableName = rsFKs.getString(3);
904                     if (tableName == null) { // this is the first one
905
tableName = temptableName;
906                         constraintNameMap = new HashMap();
907                         constraints = new ArrayList();
908                     }
909
910
911                     if (!temptableName.equals(tableName)) { // now we set everyting up for prev table
912
JdbcTable jdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
913                         JdbcConstraint[] jdbcConstraints = new JdbcConstraint[constraints.size()];
914                         constraints.toArray(jdbcConstraints);
915                         jdbcTable.constraints = jdbcConstraints;
916
917
918                         tableName = temptableName;
919                         constraintNameMap.clear();
920                         constraints.clear();
921                     }
922
923                     String JavaDoc fkName = rsFKs.getString(6);
924                     JdbcTable jdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
925
926                     if (jdbcTable == null) continue;
927
928                     if (constraintNameMap.containsKey(fkName)) {
929                         JdbcConstraint constraint = null;
930                         for (Iterator iter = constraints.iterator(); iter.hasNext();) {
931                             JdbcConstraint jdbcConstraint = (JdbcConstraint) iter.next();
932                             if (jdbcConstraint.name.equals(fkName)) {
933                                 constraint = jdbcConstraint;
934                             }
935                         }
936
937                         JdbcColumn[] tempConstraintColumns = constraint.srcCols;
938                         JdbcColumn[] constraintColumns = new JdbcColumn[tempConstraintColumns.length + 1];
939                         System.arraycopy(tempConstraintColumns, 0, constraintColumns, 0, tempConstraintColumns.length);
940                         String JavaDoc colName = rsFKs.getString(4);
941                         for (int i = 0; i < jdbcTable.cols.length; i++) {
942                             JdbcColumn jdbcColumn = jdbcTable.cols[i];
943                             if (colName.equals(jdbcColumn.name)) {
944                                 constraintColumns[tempConstraintColumns.length] = jdbcColumn;
945                                 jdbcColumn.foreignKey = true;
946                             }
947                         }
948                         constraint.srcCols = constraintColumns;
949                     } else {
950                         constraintNameMap.put(fkName, null);
951                         JdbcConstraint constraint = new JdbcConstraint();
952                         constraint.name = fkName;
953                         constraint.src = jdbcTable;
954                         String JavaDoc colName = rsFKs.getString(4);
955                         JdbcColumn[] constraintColumns = new JdbcColumn[1];
956                         for (int i = 0; i < jdbcTable.cols.length; i++) {
957                             JdbcColumn jdbcColumn = jdbcTable.cols[i];
958                             if (colName.equals(jdbcColumn.name)) {
959                                 constraintColumns[0] = jdbcColumn;
960                                 jdbcColumn.foreignKey = true;
961                             }
962                         }
963                         constraint.srcCols = constraintColumns;
964                         constraint.dest = (JdbcTable) jdbcTableMap.get(rsFKs.getString(1));
965                         constraints.add(constraint);
966                     }
967                 }
968
969                 JdbcTable constraintsjdbcTable = (JdbcTable) jdbcTableMap.get(tableName);
970                 if(constraintsjdbcTable != null) {
971                     JdbcConstraint[] jdbcConstraints = new JdbcConstraint[constraints.size()];
972                     constraints.toArray(jdbcConstraints);
973                     constraintsjdbcTable.constraints = jdbcConstraints;
974                 }
975
976                 if (rsFKs != null) {
977                     try {
978                         rsFKs.close();
979                     } catch (SQLException e) {
980                     }
981                 }
982                 if (statFK != null) {
983                     try {
984                         statFK.close();
985                     } catch (SQLException e) {
986                     }
987                 }
988             }
989         }
990
991         HashMap returnMap = new HashMap();
992         Collection col = jdbcTableMap.values();
993         String JavaDoc name = null;
994         for (Iterator iterator = col.iterator(); iterator.hasNext();) {
995             JdbcTable table = (JdbcTable) iterator.next();
996             name = table.name.toLowerCase();
997             returnMap.put(name, table);
998             if (synonymMap.containsKey(name)){
999                 returnMap.put(synonymMap.get(name), table);
1000            }
1001        }
1002        fixAllNames(returnMap);
1003        return returnMap;
1004    }
1005
1006    public boolean checkType(JdbcColumn ourCol, JdbcColumn dbCol) {
1007        String JavaDoc ourSqlType = ourCol.sqlType.toUpperCase();
1008        String JavaDoc dbSqlType = dbCol.sqlType.toUpperCase();
1009        if (ourCol.jdbcType == dbCol.jdbcType) {
1010            return true;
1011        } else if (ourSqlType.startsWith(dbSqlType)) {
1012            return true;
1013        } else {
1014            switch (ourCol.jdbcType) {
1015                case Types.SMALLINT:
1016                case Types.BIT:
1017                case Types.TINYINT:
1018                    switch (dbCol.jdbcType) {
1019                        case Types.BIT:
1020                        case Types.TINYINT:
1021                        case Types.DECIMAL:
1022                            return true;
1023                        default:
1024                            return false;
1025                    }
1026                case Types.INTEGER:
1027                    switch (dbCol.jdbcType) {
1028                        case Types.NUMERIC:
1029                        case Types.DECIMAL:
1030                            return true;
1031                        default:
1032                            return false;
1033                    }
1034
1035                default:
1036                    return super.checkType(ourCol, dbCol);
1037            }
1038        }
1039    }
1040
1041
1042    /**
1043     * Append a column that needs to be added.
1044     */

1045    protected void appendAddNewColumn(JdbcTable t, JdbcColumn c,
1046                                      CharBuf s, boolean comments) {
1047        if (comments && isCommentSupported() && c.comment != null) {
1048            s.append(comment("add column for field " + c.comment));
1049        }
1050        s.append("\n");
1051        if (isAddSequenceColumn(c)) {
1052            addSequenceColumn(t, c, s, comments);
1053        } else {
1054
1055            s.append("ALTER TABLE ");
1056            s.append(t.name);
1057            s.append(" ADD (");
1058            s.append(c.name);
1059            s.append(' ');
1060            appendColumnType(c, s);
1061            s.append(" NULL)");
1062            s.append(getRunCommand());
1063            if (!c.nulls) {
1064                s.append("UPDATE ");
1065                s.append(t.name);
1066                s.append(" SET ");
1067                s.append(c.name);
1068                s.append(" = ");
1069                s.append(getDefaultForType(c));
1070                s.append(getRunCommand());
1071
1072                s.append("ALTER TABLE ");
1073                s.append(t.name);
1074                s.append(" MODIFY ");
1075                s.append(c.name);
1076                s.append(' ');
1077                appendColumnType(c, s);
1078                appendCreateColumnNulls(t, c, s);
1079                s.append(getRunCommand());
1080            }
1081        }
1082    }
1083
1084    /**
1085     * Append a column that needs to be added.
1086     */

1087    protected void appendModifyColumn(TableDiff tableDiff, ColumnDiff diff,
1088                                      CharBuf s, boolean comments) {
1089        JdbcTable t = tableDiff.getOurTable();
1090        JdbcColumn ourCol = diff.getOurCol();
1091        boolean nulls = diff.isNullDiff();
1092
1093        if (comments && isCommentSupported() && ourCol.comment != null) {
1094            s.append(comment("modify column for field " + ourCol.comment));
1095        }
1096        if (comments && isCommentSupported() && ourCol.comment == null) {
1097            s.append(comment("modify column " + ourCol.name));
1098        }
1099
1100        s.append("\n");
1101
1102        if (nulls) {
1103            if (!ourCol.nulls) {
1104                s.append("UPDATE ");
1105                s.append(t.name);
1106                s.append("\n");
1107                s.append(" SET ");
1108                s.append(ourCol.name);
1109                s.append(" = ");
1110                s.append(getDefaultForType(ourCol));
1111                s.append("\n");
1112                s.append(" WHERE ");
1113                s.append(ourCol.name);
1114                s.append(" = NULL");
1115
1116                s.append(getRunCommand());
1117
1118            }
1119
1120        }
1121
1122        s.append("ALTER TABLE ");
1123        s.append(t.name);
1124        s.append(" MODIFY ");
1125        s.append(ourCol.name);
1126        s.append(' ');
1127        appendColumnType(ourCol, s);
1128        if (nulls) {
1129            appendCreateColumnNulls(t, ourCol, s);
1130        }
1131
1132    }
1133
1134    /**
1135     * Must this column be recreated?
1136     * @param diff
1137     * @return
1138     */

1139    private boolean mustRecreate(ColumnDiff diff) {
1140        JdbcColumn ourCol = diff.getOurCol();
1141        JdbcColumn dbCol = diff.getDbCol();
1142        boolean recreateColumn = false;
1143        if (diff.isLenghtDiff()) {
1144            if (dbCol.length > ourCol.length) {
1145                recreateColumn = true;
1146            }
1147        }
1148        if (diff.isScaleDiff()) {
1149            if (dbCol.scale > ourCol.scale) {
1150                recreateColumn = true;
1151            }
1152        }
1153        return recreateColumn;
1154    }
1155
1156    /**
1157     * Append a column that needs to be added.
1158     */

1159    protected void appendDropColumn(TableDiff tableDiff, JdbcColumn c,
1160                                    CharBuf s, boolean comments) {
1161        if (comments && isCommentSupported()) {
1162            s.append(comment("dropping unknown column " + c.name));
1163        }
1164        s.append("\n");
1165        if (isDropSequenceColumn(tableDiff, c)) {
1166            dropSequenceColumn(tableDiff.getOurTable(), c, s, comments);
1167        } else {
1168            s.append("ALTER TABLE ");
1169            s.append(tableDiff.getOurTable().name);
1170            s.append(" DROP COLUMN ");
1171            s.append(c.name);
1172        }
1173
1174    }
1175
1176    public boolean isOracleStoreProcs() {
1177        return true;
1178    }
1179
1180    boolean isDirectTypeColumnChangesSupported(JdbcColumn toCol, JdbcColumn fromCol) {
1181        switch (fromCol.jdbcType) {
1182            case Types.BIT:
1183                switch (toCol.jdbcType) {
1184                    case Types.BIT:
1185                    case Types.TINYINT:
1186                    case Types.SMALLINT:
1187                    case Types.INTEGER:
1188                    case Types.BIGINT:
1189                    case Types.FLOAT:
1190                    case Types.REAL:
1191                    case Types.DOUBLE:
1192                    case Types.NUMERIC:
1193                    case Types.DECIMAL:
1194                        return true;
1195                    default:
1196                        return false;
1197                }
1198            case Types.TINYINT:
1199                switch (toCol.jdbcType) {
1200                    case Types.BIT:
1201                    case Types.TINYINT:
1202                    case Types.SMALLINT:
1203                    case Types.INTEGER:
1204                    case Types.BIGINT:
1205                    case Types.FLOAT:
1206                    case Types.REAL:
1207                    case Types.DOUBLE:
1208                    case Types.NUMERIC:
1209                    case Types.DECIMAL:
1210                        return true;
1211                    default:
1212                        return false;
1213                }
1214            case Types.SMALLINT:
1215                switch (toCol.jdbcType) {
1216                    case Types.BIT:
1217                    case Types.TINYINT:
1218                    case Types.SMALLINT:
1219                    case Types.INTEGER:
1220                    case Types.BIGINT:
1221                    case Types.FLOAT:
1222                    case Types.REAL:
1223                    case Types.DOUBLE:
1224                    case Types.NUMERIC:
1225                    case Types.DECIMAL:
1226                        return true;
1227                    default:
1228                        return false;
1229                }
1230            case Types.INTEGER:
1231                switch (toCol.jdbcType) {
1232                    case Types.BIT:
1233                    case Types.TINYINT:
1234                    case Types.SMALLINT:
1235                    case Types.INTEGER:
1236                    case Types.BIGINT:
1237                    case Types.FLOAT:
1238                    case Types.REAL:
1239                    case Types.DOUBLE:
1240                    case Types.NUMERIC:
1241                    case Types.DECIMAL:
1242                        return true;
1243                    default:
1244                        return false;
1245                }
1246            case Types.BIGINT:
1247                switch (toCol.jdbcType) {
1248                    case Types.BIT:
1249                    case Types.TINYINT:
1250                    case Types.SMALLINT:
1251                    case Types.INTEGER:
1252                    case Types.BIGINT:
1253                    case Types.FLOAT:
1254                    case Types.REAL:
1255                    case Types.DOUBLE:
1256                    case Types.NUMERIC:
1257                    case Types.DECIMAL:
1258                        return true;
1259                    default:
1260                        return false;
1261                }
1262            case Types.FLOAT:
1263                switch (toCol.jdbcType) {
1264                    case Types.BIT:
1265                    case Types.TINYINT:
1266                    case Types.SMALLINT:
1267                    case Types.INTEGER:
1268                    case Types.BIGINT:
1269                    case Types.FLOAT:
1270                    case Types.REAL:
1271                    case Types.DOUBLE:
1272                    case Types.NUMERIC:
1273                    case Types.DECIMAL:
1274                        return true;
1275                    default:
1276                        return false;
1277                }
1278            case Types.REAL:
1279                switch (toCol.jdbcType) {
1280                    case Types.BIT:
1281                    case Types.TINYINT:
1282                    case Types.SMALLINT:
1283                    case Types.INTEGER:
1284                    case Types.BIGINT:
1285                    case Types.FLOAT:
1286                    case Types.REAL:
1287                    case Types.DOUBLE:
1288                    case Types.NUMERIC:
1289                    case Types.DECIMAL:
1290                        return true;
1291                    default:
1292                        return false;
1293                }
1294            case Types.DOUBLE:
1295                switch (toCol.jdbcType) {
1296                    case Types.BIT:
1297                    case Types.TINYINT:
1298                    case Types.SMALLINT:
1299                    case Types.INTEGER:
1300                    case Types.BIGINT:
1301                    case Types.FLOAT:
1302                    case Types.REAL:
1303                    case Types.DOUBLE:
1304                    case Types.NUMERIC:
1305                    case Types.DECIMAL:
1306                        return true;
1307                    default:
1308                        return false;
1309                }
1310            case Types.NUMERIC:
1311                switch (toCol.jdbcType) {
1312                    case Types.BIT:
1313                    case Types.TINYINT:
1314                    case Types.SMALLINT:
1315                    case Types.INTEGER:
1316                    case Types.BIGINT:
1317                    case Types.FLOAT:
1318                    case Types.REAL:
1319                    case Types.DOUBLE:
1320                    case Types.NUMERIC:
1321                    case Types.DECIMAL:
1322                        return true;
1323                    default:
1324                        return false;
1325                }
1326            case Types.DECIMAL:
1327                switch (toCol.jdbcType) {
1328                    case Types.BIT:
1329                    case Types.TINYINT:
1330                    case Types.SMALLINT:
1331                    case Types.INTEGER:
1332                    case Types.BIGINT:
1333                    case Types.FLOAT:
1334                    case Types.REAL:
1335                    case Types.DOUBLE:
1336                    case Types.NUMERIC:
1337                    case Types.DECIMAL:
1338                        return true;
1339                    default:
1340                        return false;
1341                }
1342            case Types.CHAR:
1343                switch (toCol.jdbcType) {
1344                    case Types.VARCHAR:
1345                    case Types.CHAR:
1346                        return true;
1347                    default:
1348                        return false;
1349                }
1350            case Types.VARCHAR:
1351                switch (toCol.jdbcType) {
1352                    case Types.VARCHAR:
1353                    case Types.CHAR:
1354                        return true;
1355                    default:
1356                        return false;
1357                }
1358            case Types.DATE:
1359                switch (toCol.jdbcType) {
1360                    case Types.TIMESTAMP:
1361                    case Types.DATE:
1362                    case Types.TIME:
1363                        return true;
1364                    default:
1365                        return false;
1366                }
1367            case Types.TIME:
1368                switch (toCol.jdbcType) {
1369                    case Types.TIMESTAMP:
1370                    case Types.DATE:
1371                    case Types.TIME:
1372                        return true;
1373                    default:
1374                        return false;
1375                }
1376            case Types.TIMESTAMP:
1377                switch (toCol.jdbcType) {
1378                    case Types.TIMESTAMP:
1379                    case Types.DATE:
1380                    case Types.TIME:
1381                        return true;
1382                    default:
1383                        return false;
1384                }
1385            case Types.CLOB:
1386            case Types.LONGVARCHAR:
1387            case Types.BLOB:
1388            case Types.LONGVARBINARY:
1389            case Types.VARBINARY:
1390                /*
1391                todo we need to throw a exception if this happens, because we cannot support this changes.
1392                */

1393
1394
1395
1396        }
1397        return false;
1398    }
1399
1400
1401    boolean isDirectScaleColumnChangesSupported(JdbcColumn ourCol, JdbcColumn dbCol) {
1402        if (dbCol.scale < ourCol.scale) {
1403            return true;
1404        }
1405        return false;
1406    }
1407
1408    boolean isDirectLenghtColumnChangesSupported(JdbcColumn ourCol, JdbcColumn dbCol) {
1409        if (dbCol.length < ourCol.length) {
1410            return true;
1411        }
1412        return false;
1413    }
1414
1415    /**
1416     * Append an 'drop constraint' statement for c.
1417     */

1418    protected void appendRefDropConstraint(CharBuf s, JdbcConstraint c, boolean comments) {
1419        s.append("ALTER TABLE ");
1420        s.append(c.src.name);
1421        s.append(" DROP CONSTRAINT ");
1422        s.append(c.name);
1423    }
1424
1425    /**
1426     * Generate a 'drop index' statement for idx.
1427     */

1428    protected void appendDropIndex(CharBuf s, JdbcTable t, JdbcIndex idx,
1429                                   boolean comments) {
1430        s.append("DROP INDEX ");
1431        s.append(idx.name);
1432    }
1433
1434    /**
1435     * Add the primary key constraint in isolation.
1436     */

1437    protected void addPrimaryKeyConstraint(JdbcTable t, CharBuf s) {
1438        s.append("ALTER TABLE ");
1439        s.append(t.name);
1440        s.append(" ADD ");
1441        appendPrimaryKeyConstraint(t, s);
1442    }
1443
1444    /**
1445     * Drop the primary key constraint in isolation.
1446     */

1447    protected void dropPrimaryKeyConstraint(JdbcTable t, CharBuf s) {
1448        s.append("ALTER TABLE ");
1449        s.append(t.name);
1450        s.append(" DROP CONSTRAINT ");
1451        s.append(t.pkConstraintName);
1452    }
1453
1454    protected void fixColumnsNonDirect(TableDiff tableDiff, PrintWriter JavaDoc out) {
1455
1456        JdbcTable ourTable = tableDiff.getOurTable();
1457        String JavaDoc tempTableName = getTempTableName(ourTable,30);
1458
1459
1460        CharBuf s = new CharBuf();
1461
1462        JdbcTable dbTable = tableDiff.getDbTable();
1463        if (dbTable.pkConstraintName != null) {
1464            if (tableDiff.getPkDiffs().isEmpty()) {
1465                dropPrimaryKeyConstraint(tableDiff.getDbTable(), s);
1466                s.append(getRunCommand());
1467            }
1468        }
1469
1470        s.append("CREATE TABLE ");
1471        s.append(tempTableName);
1472        s.append(" (\n");
1473        JdbcColumn[] cols = ourTable.getColsForCreateTable();
1474        int nc = cols.length;
1475        boolean first = true;
1476        for (int i = 0; i < nc; i++) {
1477            if (first) {
1478                first = false;
1479            } else {
1480                s.append("\n");
1481            }
1482            s.append(" ");
1483            appendCreateColumn(ourTable, cols[i], s, true);
1484        }
1485        s.append("\n ");
1486        appendPrimaryKeyConstraint(ourTable, s);
1487        s.append("\n)");
1488
1489
1490        s.append(getRunCommand());
1491
1492
1493        s.append("INSERT INTO ");
1494        s.append(tempTableName); //
1495
s.append(" (");
1496        for (int i = 0; i < nc; i++) {
1497            s.append(cols[i].name);
1498            if ((i + 1) != nc) {
1499                s.append(", ");
1500            }
1501        }
1502        s.append(") ");
1503
1504        s.append("\n");
1505
1506        s.append("SELECT ");
1507        for (int i = 0; i < nc; i++) {
1508            JdbcColumn ourCol = cols[i];
1509            ColumnDiff diff = getColumnDiffForName(tableDiff, ourCol.name);
1510            if (diff == null) {
1511                if (i != 0) {
1512                    s.append(" ");
1513                }
1514                s.append(ourCol.name);
1515            } else {
1516                JdbcColumn dbCol = diff.getDbCol();
1517                if (diff.isMissingCol()) {
1518                    if (diff.getOurCol().nulls) {
1519                        if (i != 0) {
1520                            s.append(" ");
1521                        }
1522                        s.append("NULL");
1523
1524                    } else {
1525                        if (i != 0) {
1526                            s.append(" ");
1527                        }
1528                        s.append(getDefaultForType(diff.getOurCol()));
1529                    }
1530
1531                } else if ((diff.isLenghtDiff() || diff.isScaleDiff() || diff.isTypeDiff()) && diff.isNullDiff()) {
1532
1533                    if (ourCol.nulls) {
1534                        if (i != 0) {
1535                            s.append(" ");
1536                        }
1537                        appendCast(ourCol, dbCol, s, false);
1538                    } else {
1539                        if (i != 0) {
1540                            s.append(" ");
1541                        }
1542                        s.append("CASE ");
1543                        s.append("\n");//new line
1544
s.append(" WHEN ");
1545                        s.append(ourCol.name);
1546                        s.append(" IS NOT NULL THEN ");
1547                        appendCast(ourCol, dbCol, s, false);
1548                        s.append("\n");//new line
1549
s.append(" ELSE ");
1550                        appendCast(ourCol, dbCol, s, true);
1551                        s.append("\n");//new line
1552
s.append(" END");
1553                    }
1554
1555                } else if ((diff.isLenghtDiff() || diff.isScaleDiff() || diff.isTypeDiff()) && !diff.isNullDiff()) {
1556                    if (i != 0) {
1557                        s.append(" ");
1558                    }
1559                    appendCast(ourCol, dbCol, s, true);
1560                } else if (diff.isNullDiff()) {
1561                    if (ourCol.nulls) {
1562                        if (i != 0) {
1563                            s.append(" ");
1564                        }
1565                        s.append(ourCol.name);
1566                    } else {
1567                        if (i != 0) {
1568                            s.append(" ");
1569                        }
1570                        s.append("CASE ");
1571                        s.append("\n");//new line
1572
s.append(" WHEN ");
1573                        s.append(ourCol.name);
1574                        s.append(" IS NOT NULL THEN ");
1575                        s.append(ourCol.name);
1576                        s.append("\n");//new line
1577
s.append(" ELSE ");
1578                        s.append(getDefaultForType(ourCol));
1579                        s.append("\n");//new line
1580
s.append(" END");
1581                    }
1582                }
1583            }
1584
1585
1586            if ((i + 1) != nc) {
1587                s.append(", ");
1588                s.append("\n");//new line
1589
}
1590        }
1591        s.append("\n");//new line
1592
s.append(" FROM ");
1593        s.append(ourTable.name);
1594        s.append(getRunCommand());
1595
1596
1597        s.append("DROP TABLE ");
1598        s.append(ourTable.name);
1599        s.append(" CASCADE CONSTRAINTS");
1600        s.append(getRunCommand());
1601
1602        s.append("ALTER TABLE ");
1603        s.append(tempTableName);
1604        s.append(" RENAME TO ");
1605        s.append(ourTable.name);
1606        s.append(getRunCommand());
1607
1608        out.println(s.toString());
1609
1610
1611    }
1612
1613    private void appendCast(JdbcColumn ourCol, JdbcColumn dbCol, CharBuf s, boolean defaultValue) {
1614        String JavaDoc ourType = ourCol.sqlType.toUpperCase().trim();
1615        String JavaDoc dbType = dbCol.sqlType.toUpperCase().trim();
1616
1617        if ((ourType.startsWith("VARCHAR2") || ourType.startsWith("CHAR")) && (
1618                dbType.startsWith("VARCHAR2") ||
1619                dbType.startsWith("CHAR") ||
1620                dbType.startsWith("NCHAR"))) {
1621            s.append("CAST(TRANSLATE(");
1622            if (defaultValue) {
1623                s.append(getDefaultForType(ourCol));
1624            } else {
1625                s.append(ourCol.name);
1626            }
1627            s.append(" USING CHAR_CS) AS ");
1628            appendColumnType(ourCol, s);
1629            s.append(")");
1630        } else if (ourType.startsWith("NCHAR") && (
1631                dbType.startsWith("VARCHAR2") ||
1632                dbType.startsWith("CHAR") ||
1633                dbType.startsWith("NCHAR"))) {
1634
1635            s.append("CAST(TRANSLATE(");
1636            if (defaultValue) {
1637                s.append(getDefaultForType(ourCol));
1638            } else {
1639                s.append(ourCol.name);
1640            }
1641            s.append(" USING NCHAR_CS) AS ");
1642            appendColumnType(ourCol, s);
1643            s.append(")");
1644        } else if ((ourType.startsWith("CLOB") || (ourType.startsWith("BLOB"))) && (
1645                dbType.startsWith("LONG"))) {
1646            if (defaultValue) {
1647                s.append(getDefaultForType(ourCol));
1648            } else {
1649                s.append("TO_LOB(");
1650                s.append(ourCol.name);
1651                s.append(")");
1652            }
1653        } else {
1654            s.append("CAST(");
1655            if (defaultValue) {
1656                s.append(getDefaultForType(ourCol));
1657            } else {
1658                s.append(ourCol.name);
1659            }
1660            s.append(" AS ");
1661            appendColumnType(ourCol, s);
1662            s.append(")");
1663        }
1664    }
1665
1666    /**
1667     * Drop a Sequence column to implement a Set
1668     */

1669    protected void dropSequenceColumn(JdbcTable t, JdbcColumn c, CharBuf s, boolean comments) {
1670        String JavaDoc tempTableName = getTempTableName(t, 30);
1671
1672        s.append(comment("create a temp table to store old table values."));
1673        s.append("\n");
1674        s.append("CREATE TABLE ");
1675        s.append(tempTableName);
1676        s.append(" (\n");
1677        JdbcColumn[] cols = t.getColsForCreateTable();
1678        int nc = cols.length;
1679        boolean first = true;
1680        for (int i = 0; i < nc; i++) {
1681            if (first)
1682                first = false;
1683            else
1684                s.append("\n");
1685            s.append(" ");
1686            appendCreateColumn(t, cols[i], s, comments);
1687        }
1688        s.append("\n ");
1689        appendPrimaryKeyConstraint(t, s);
1690        s.append("\n)");
1691        s.append(getRunCommand());
1692
1693
1694        s.append(comment("insert a distinct list into the temp table."));
1695        s.append("\n");
1696        s.append("INSERT INTO ");
1697        s.append(tempTableName);
1698        s.append("(");
1699        for (int i = 0; i < nc; i++) {
1700            s.append(cols[i].name);
1701            if ((i + 1) != nc) {
1702                s.append(", ");
1703            }
1704        }
1705        s.append(")");
1706        s.append("\nSELECT DISTINCT ");
1707        for (int i = 0; i < nc; i++) {
1708            if (i != 0) {
1709                s.append("\n ");
1710            }
1711            s.append(cols[i].name);
1712            if ((i + 1) != nc) {
1713                s.append(", ");
1714            }
1715        }
1716        s.append("\n FROM ");
1717        s.append(t.name);
1718
1719        s.append(getRunCommand());
1720
1721
1722        s.append(comment("drop main table."));
1723        s.append("\n");
1724        s.append("DROP TABLE ");
1725        s.append(t.name);
1726        s.append(getRunCommand());
1727
1728        s.append(comment("rename temp table to main table."));
1729        s.append("\n");
1730        s.append("ALTER TABLE ");
1731        s.append(tempTableName);
1732        s.append(" RENAME TO ");
1733        s.append(t.name);
1734
1735    }
1736
1737
1738    /**
1739     * Add a Sequence column to implement a List
1740     */

1741    protected void addSequenceColumn(JdbcTable t, JdbcColumn c, CharBuf s, boolean comments) {
1742        String JavaDoc tempTableName = getTempTableName(t, 30);
1743        String JavaDoc minTempTableName = getTempTableName(t, 30);
1744
1745        JdbcColumn indexColumn = null;
1746        JdbcColumn sequenceColumn = null;
1747        JdbcColumn[] cols = t.getColsForCreateTable();
1748        int nc = cols.length;
1749        for (int i = 0; i < nc; i++) {
1750            if (isAddSequenceColumn(cols[i])) {
1751                sequenceColumn = cols[i];
1752            } else if (t.isInPrimaryKey(cols[i].name)) {
1753                indexColumn = cols[i];
1754            }
1755        }
1756
1757
1758        s.append(comment("create a temp table to store old table values."));
1759        s.append("\n");
1760        s.append("CREATE TABLE ");
1761        s.append(tempTableName);
1762        s.append(" (\n");
1763        boolean first = true;
1764        for (int i = 0; i < nc; i++) {
1765            if (first) {
1766                first = false;
1767            } else {
1768                s.append("\n");
1769            }
1770            s.append(" ");
1771            appendCreateColumn(t, cols[i], s, true);
1772        }
1773        int lastIndex = s.toString().lastIndexOf(',');
1774        s.replace(lastIndex, lastIndex + 1, ' ');// we take the last ',' out.
1775
s.append("\n)");
1776        s.append(getRunCommand());
1777
1778
1779        s.append(comment("create a temp table to store the minimum id."));
1780        s.append("\n");
1781        s.append("CREATE TABLE ");
1782        s.append(minTempTableName);
1783        s.append(" (\n ");
1784        s.append(indexColumn.name);
1785        s.append(' ');
1786        appendColumnType(indexColumn, s);
1787        appendCreateColumnNulls(t, indexColumn, s);
1788        s.append(",\n ");
1789        s.append("min_id");
1790        s.append(" INTEGER\n)");
1791
1792
1793        s.append(getRunCommand());
1794
1795
1796        s.append(comment("insert a sequence, and copy the rest of the old table into the temp table."));
1797        s.append("\n");
1798        s.append("INSERT INTO ");
1799        s.append(tempTableName);
1800        s.append("(");
1801        for (int i = 0; i < nc; i++) {
1802            s.append(cols[i].name);
1803            if ((i + 1) != nc) {
1804                s.append(", ");
1805            }
1806        }
1807        s.append(")");
1808        s.append("\nSELECT ");
1809        for (int i = 0; i < nc; i++) {
1810            if (i != 0) {
1811                s.append("\n ");
1812            }
1813            if (isAddSequenceColumn(cols[i])) {
1814                s.append('0');
1815            } else {
1816                s.append(cols[i].name);
1817            }
1818            if ((i + 1) != nc) {
1819                s.append(", ");
1820            }
1821        }
1822        s.append("\n FROM ");
1823        s.append(t.name);
1824        s.append("\n ORDER BY ");
1825        s.append(indexColumn.name);
1826
1827
1828
1829        s.append(getRunCommand());
1830
1831
1832        s.append(comment("store the minimum id."));
1833        s.append("\n");
1834        s.append("UPDATE ");
1835        s.append(tempTableName);
1836        s.append("\n SET ");
1837        s.append(c.name);
1838        s.append(" = ROWNUM");
1839        s.append(getRunCommand());
1840
1841
1842        s.append(comment("store the minimum id."));
1843        s.append("\n");
1844        s.append("INSERT INTO ");
1845        s.append(minTempTableName);
1846        s.append(" (");
1847        s.append(indexColumn.name);
1848        s.append(", ");
1849        s.append("min_id");
1850        s.append(")\n");
1851        s.append("SELECT ");
1852        s.append(indexColumn.name);
1853        s.append(",\n ");
1854        s.append("MIN(" +
1855                c.name + //"ROWNUM" +
1856
")\n");
1857        s.append(" FROM ");
1858        s.append(tempTableName);
1859        s.append("\n");
1860        s.append(" GROUP BY ");
1861        s.append(indexColumn.name);
1862
1863
1864        s.append(getRunCommand());
1865
1866
1867
1868        s.append(comment("update the sequence column."));
1869        s.append("\n");
1870        s.append("UPDATE ");
1871        s.append(tempTableName);
1872        s.append(" a\n SET ");
1873        s.append(c.name);
1874        s.append(" = (SELECT a.");
1875        s.append(c.name);
1876        s.append(" - b.min_id\n");
1877        s.append(pad(13+ c.name.length()));
1878        s.append("FROM ");
1879        s.append(minTempTableName);
1880        s.append(" b\n");
1881        s.append(pad(12 + c.name.length()));
1882        s.append("WHERE a.");
1883        s.append(indexColumn.name);
1884        s.append(" = b.");
1885        s.append(indexColumn.name);
1886        s.append(')');
1887
1888
1889        s.append(getRunCommand());
1890
1891        s.append(comment("drop temp table."));
1892        s.append("\n");
1893        s.append("DROP TABLE ");
1894        s.append(minTempTableName);
1895        s.append(getRunCommand());
1896
1897        s.append(comment("drop main table."));
1898        s.append("\n");
1899        s.append("DROP TABLE ");
1900        s.append(t.name);
1901        s.append(getRunCommand());
1902
1903        s.append(comment("rename temp table to main table."));
1904        s.append("\n");
1905        s.append("ALTER TABLE ");
1906        s.append(tempTableName);
1907        s.append(" RENAME TO ");
1908        s.append(t.name);
1909        s.append(getRunCommand());
1910
1911        s.append(comment("Add the primary key back."));
1912        s.append("\n");
1913        addPrimaryKeyConstraint(t,s);
1914        s.append(getRunCommand());
1915
1916
1917    }
1918
1919}
1920
Popular Tags