001: /*
002: * Copyright (C) 2005 Rob Manning
003: * manningr@users.sourceforge.net
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package net.sourceforge.squirrel_sql.plugins.dbdiff.util;
021:
022: import java.sql.Connection;
023: import java.sql.DatabaseMetaData;
024: import java.sql.ResultSet;
025: import java.sql.SQLException;
026: import java.sql.Statement;
027: import java.sql.Types;
028: import java.util.ArrayList;
029: import java.util.Iterator;
030: import java.util.List;
031:
032: import net.sourceforge.squirrel_sql.client.session.ISession;
033: import net.sourceforge.squirrel_sql.client.session.schemainfo.SchemaInfo;
034: import net.sourceforge.squirrel_sql.fw.dialects.DialectFactory;
035: import net.sourceforge.squirrel_sql.fw.dialects.HibernateDialect;
036: import net.sourceforge.squirrel_sql.fw.dialects.UserCancelledOperationException;
037: import net.sourceforge.squirrel_sql.fw.sql.ForeignKeyInfo;
038: import net.sourceforge.squirrel_sql.fw.sql.ISQLConnection;
039: import net.sourceforge.squirrel_sql.fw.sql.ITableInfo;
040: import net.sourceforge.squirrel_sql.fw.sql.JDBCTypeMapper;
041: import net.sourceforge.squirrel_sql.fw.sql.SQLDatabaseMetaData;
042: import net.sourceforge.squirrel_sql.fw.sql.SQLUtilities;
043: import net.sourceforge.squirrel_sql.fw.sql.TableColumnInfo;
044: import net.sourceforge.squirrel_sql.fw.util.StringManager;
045: import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory;
046: import net.sourceforge.squirrel_sql.fw.util.log.ILogger;
047: import net.sourceforge.squirrel_sql.fw.util.log.LoggerController;
048: import net.sourceforge.squirrel_sql.plugins.dbdiff.I18NBaseObject;
049: import net.sourceforge.squirrel_sql.plugins.dbdiff.SessionInfoProvider;
050:
051: import org.hibernate.MappingException;
052:
053: /**
054: * A utility class for interacting with the database.
055: */
056: public class DBUtil extends I18NBaseObject {
057:
058: /** Logger for this class. */
059: private final static ILogger log = LoggerController
060: .createLogger(DBUtil.class);
061:
062: /** Internationalized strings for this class */
063: private static final StringManager s_stringMgr = StringManagerFactory
064: .getStringManager(DBUtil.class);
065:
066: /** The last statement executed that we'll show to the user if error */
067: private static String lastStatement = null;
068:
069: private static String lastStatementValues = null;
070:
071: /**
072: * Returns a string that looks like:
073: *
074: * (PK_COL1, PK_COL2, PK_COL3, ...)
075: *
076: * or null if there is no primary key for the specified table.
077: *
078: * @param sourceConn
079: * @param ti
080: * @return
081: * @throws SQLException
082: */
083: public static String getPKColumnString(ISQLConnection sourceConn,
084: ITableInfo ti) throws SQLException {
085: List<String> pkColumns = getPKColumnList(sourceConn, ti);
086: if (pkColumns == null || pkColumns.size() == 0) {
087: return null;
088: }
089: StringBuffer sb = new StringBuffer("(");
090: Iterator<String> i = pkColumns.iterator();
091: while (i.hasNext()) {
092: String columnName = i.next();
093: sb.append(columnName);
094: if (i.hasNext()) {
095: sb.append(", ");
096: }
097: }
098: sb.append(")");
099: return sb.toString();
100: }
101:
102: /**
103: * Returns a list of primary keys or null if there are no primary keys for
104: * the specified table.
105: *
106: * @param sourceConn
107: * @param ti
108: * @return
109: * @throws SQLException
110: */
111: private static List<String> getPKColumnList(
112: ISQLConnection sourceConn, ITableInfo ti)
113: throws SQLException {
114: ArrayList<String> pkColumns = new ArrayList<String>();
115: DatabaseMetaData md = sourceConn.getConnection().getMetaData();
116: ResultSet rs = null;
117: if (md.supportsCatalogsInTableDefinitions()) {
118: rs = md.getPrimaryKeys(ti.getCatalogName(), null, ti
119: .getSimpleName());
120: } else if (md.supportsSchemasInTableDefinitions()) {
121: rs = md.getPrimaryKeys(null, ti.getSchemaName(), ti
122: .getSimpleName());
123: } else {
124: rs = md.getPrimaryKeys(null, null, ti.getSimpleName());
125: }
126: while (rs.next()) {
127: String keyColumn = rs.getString(4);
128: if (keyColumn != null) {
129: pkColumns.add(keyColumn);
130: }
131: }
132: if (pkColumns.size() == 0) {
133: return null;
134: }
135: return pkColumns;
136: }
137:
138: public static boolean tableHasForeignKey(String destCatalog,
139: String destSchema, String destTableName,
140: ForeignKeyInfo fkInfo, SessionInfoProvider prov) {
141: boolean result = false;
142: try {
143: SQLDatabaseMetaData md = prov.getDiffDestSession()
144: .getSQLConnection().getSQLMetaData();
145:
146: ITableInfo[] tables = md.getTables(destCatalog, destSchema,
147: destTableName, new String[] { "TABLE" }, null);
148: if (tables != null && tables.length == 1) {
149: ForeignKeyInfo[] fks = SQLUtilities.getImportedKeys(
150: tables[0], md);
151: for (ForeignKeyInfo existingKey : fks) {
152: if (areEqual(existingKey, fkInfo)) {
153: result = true;
154: break;
155: }
156: }
157: } else {
158: log
159: .error("Couldn't find an exact match for destination table "
160: + destTableName
161: + " in schema "
162: + destSchema
163: + " and catalog "
164: + destCatalog
165: + ". Skipping FK constraint");
166: }
167: } catch (SQLException e) {
168: log
169: .error("Unexpected exception while attempting to determine if "
170: + "a table ("
171: + destTableName
172: + ") has a particular foreign " + "key");
173: }
174: return result;
175: }
176:
177: private static boolean areEqual(ForeignKeyInfo fk1,
178: ForeignKeyInfo fk2) {
179: String fk1FKColumn = fk1.getForeignKeyColumnName();
180: String fk2FKColumn = fk2.getForeignKeyColumnName();
181: String fk1PKColumn = fk1.getPrimaryKeyColumnName();
182: String fk2PKColumn = fk2.getPrimaryKeyColumnName();
183: String fk1FKTable = fk1.getForeignKeyTableName();
184: String fk2FKTable = fk2.getForeignKeyTableName();
185: String fk1PKTable = fk1.getPrimaryKeyTableName();
186: String fk2PKTable = fk2.getPrimaryKeyTableName();
187:
188: if (!fk1PKColumn.equals(fk2PKColumn)) {
189: return false;
190: }
191: if (!fk1FKColumn.equals(fk2FKColumn)) {
192: return false;
193: }
194: if (!fk1PKTable.equals(fk2PKTable)) {
195: return false;
196: }
197: if (!fk1FKTable.equals(fk2FKTable)) {
198: return false;
199: }
200: return true;
201: }
202:
203: public static boolean containsTable(List<ITableInfo> tableInfos,
204: String table) {
205: boolean result = false;
206: for (ITableInfo ti : tableInfos) {
207: if (table.equalsIgnoreCase(ti.getSimpleName())) {
208: result = true;
209: break;
210: }
211: }
212: return result;
213: }
214:
215: /**
216: * Executes the specified sql statement on the specified connection and
217: * returns the ResultSet.
218: *
219: * @param con
220: * @param sql
221: * @param mysqlBigResultFix if true, provides a work-around which is useful
222: * in the case that the connection is to a MySQL database. If the
223: * number of rows is large this will prevent the driver from reading
224: * them all into client memory. MySQL's normal practice is to do
225: * such a thing for performance reasons.
226: * @return
227: * @throws Exception
228: */
229: public static ResultSet executeQuery(ISession session, String sql)
230: throws SQLException {
231: ISQLConnection sqlcon = session.getSQLConnection();
232: if (sqlcon == null || sql == null) {
233: return null;
234: }
235: Statement stmt = null;
236: ResultSet rs = null;
237:
238: Connection con = sqlcon.getConnection();
239: try {
240: stmt = con.createStatement();
241: } catch (SQLException e) {
242: // Only close the statement if SQLException - otherwise it has to
243: // remain open until the ResultSet is read through by the caller.
244: if (stmt != null) {
245: try {
246: stmt.close();
247: } catch (SQLException ex) { /* Do Nothing */
248: }
249: }
250: throw e;
251: }
252: if (log.isDebugEnabled()) {
253: //i18n[DBUtil.info.executequery=executeQuery: Running SQL:\n '{0}']
254: String msg = s_stringMgr.getString(
255: "DBUtil.info.executequery", sql);
256: log.debug(msg);
257: }
258: try {
259: lastStatement = sql;
260: rs = stmt.executeQuery(sql);
261: } catch (SQLException e) {
262: // Only close the statement if SQLException - otherwise it has to
263: // remain open until the ResultSet is read through by the caller.
264: if (stmt != null) {
265: try {
266: stmt.close();
267: } catch (SQLException ex) { /* Do Nothing */
268: }
269: }
270: throw e;
271: }
272:
273: return rs;
274: }
275:
276: /**
277: * Closes the specified ResultSet.
278: *
279: * @param rs the ResultSet to close.
280: */
281: public static void closeResultSet(ResultSet rs) {
282: if (rs == null) {
283: return;
284: }
285: try {
286: Statement stmt = rs.getStatement();
287: closeStatement(stmt);
288: } catch (Exception e) { /* Do Nothing */
289: }
290: }
291:
292: /**
293: * Closes the specified Statement.
294: *
295: * @param stmt the Statement to close.
296: */
297: public static void closeStatement(Statement stmt) {
298: if (stmt != null) {
299: try {
300: ResultSet rs = stmt.getResultSet();
301: if (rs != null) {
302: rs.close();
303: }
304: } catch (SQLException e) {
305: }
306: try {
307: stmt.close();
308: } catch (SQLException e) {
309: }
310: }
311: }
312:
313: /**
314: * Returns a count of the records in the specified table.
315: *
316: * @param con the SQLConnection to use to execute the count query.
317: * @param tableName the name of the table. This name should already be
318: * qualified by the schema.
319: *
320: * @return -1 if the table does not exist, otherwise the record count is
321: * returned.
322: */
323: private static int getTableCount(ISession session, String tableName) {
324: int result = -1;
325: ResultSet rs = null;
326: try {
327: String sql = "select count(*) from " + tableName;
328: rs = executeQuery(session, sql);
329: if (rs.next()) {
330: result = rs.getInt(1);
331: }
332: } catch (Exception e) {
333: /* Do Nothing - this can happen when the table doesn't exist */
334: } finally {
335: closeResultSet(rs);
336: }
337: return result;
338: }
339:
340: /**
341: * Returns a count of the records in the specified table.
342: *
343: * @param con the SQLConnection to use to execute the count query.
344: * @param tableName the name of the table
345: *
346: * @return -1 if the table does not exist, otherwise the record count is
347: * returned.
348: */
349: public static int getTableCount(ISession session, String catalog,
350: String schema, String tableName, int sessionType)
351: throws UserCancelledOperationException {
352: String table = getQualifiedObjectName(session, catalog, schema,
353: tableName, sessionType);
354: return getTableCount(session, table);
355: }
356:
357: public static ITableInfo getTableInfo(ISession session,
358: String schema, String tableName) throws SQLException,
359: MappingException, UserCancelledOperationException {
360: ISQLConnection con = session.getSQLConnection();
361: SchemaInfo schemaInfo = session.getSchemaInfo();
362: // Currently, as of milestone 3, Axion doesn't support "schemas" like
363: // other databases. So, set the schema to emtpy string if we detect
364: // an Axion session.
365: if (con.getSQLMetaData().getDriverName().toLowerCase()
366: .startsWith("axion")) {
367: schema = "";
368: }
369: String catalog = null;
370: // MySQL uses catalogs and not schemas
371: if (DialectFactory.isMySQL(session.getMetaData())) {
372: catalog = schema;
373: schema = null;
374: }
375: // trim the table name in case of HADB
376: tableName = tableName.trim();
377: ITableInfo[] tis = schemaInfo.getITableInfos(catalog, schema,
378: tableName);
379:
380: if (tis == null || tis.length == 0) {
381: if (Character.isUpperCase(tableName.charAt(0))) {
382: tableName = tableName.toLowerCase();
383: } else {
384: tableName = tableName.toUpperCase();
385: }
386: tis = schemaInfo.getITableInfos(null, schema, tableName);
387: if (tis.length == 0) {
388: if (Character.isUpperCase(tableName.charAt(0))) {
389: tableName = tableName.toLowerCase();
390: } else {
391: tableName = tableName.toUpperCase();
392: }
393: tis = schemaInfo
394: .getITableInfos(null, schema, tableName);
395: }
396: }
397: if (tis.length == 0) {
398: //i18n[DBUtil.error.tablenotfound=Couldn't locate table '{0}' in
399: //schema '(1)']
400: String msg = s_stringMgr.getString(
401: "DBUtil.error.tablenotfound", new String[] {
402: tableName, schema });
403: throw new MappingException(msg);
404: }
405: if (tis.length > 1) {
406: if (log.isDebugEnabled()) {
407: log.debug("DBUtil.getTableInfo: found " + tis.length
408: + " that matched " + "catalog=" + catalog
409: + " schema=" + schema + " tableName="
410: + tableName);
411: }
412: }
413: return tis[0];
414: }
415:
416: /**
417: * Takes the specified colInfo, gets the data type to see if it is
418: * 1111(OTHER). If so then get the type name and try to match a jdbc type
419: * with the same name to get it's type code.
420: *
421: * @param colInfo
422: * @return
423: * @throws MappingException
424: */
425: public static int replaceOtherDataType(TableColumnInfo colInfo)
426: throws MappingException {
427: int colJdbcType = colInfo.getDataType();
428: if (colJdbcType == java.sql.Types.OTHER) {
429: String typeName = colInfo.getTypeName().toUpperCase();
430: int parenIndex = typeName.indexOf("(");
431: if (parenIndex != -1) {
432: typeName = typeName.substring(0, parenIndex);
433: }
434: colJdbcType = JDBCTypeMapper.getJdbcType(typeName);
435: if (colJdbcType == Types.NULL) {
436: throw new MappingException(
437: "Encoutered jdbc type OTHER (1111) and couldn't map "
438: + "the database-specific type name ("
439: + typeName + ") to a jdbc type");
440: }
441: }
442: return colJdbcType;
443: }
444:
445: /**
446: *
447: * @param con
448: * @param synonym
449: * @param columnName
450: * @return
451: * @throws SQLException
452: */
453: public static int getColumnType(ISQLConnection con, ITableInfo ti,
454: String columnName) throws SQLException {
455: int result = -1;
456: if (ti != null) {
457: TableColumnInfo[] tciArr = con.getSQLMetaData()
458: .getColumnInfo(ti);
459: for (int i = 0; i < tciArr.length; i++) {
460: if (tciArr[i].getColumnName().equalsIgnoreCase(
461: columnName)) {
462: result = tciArr[i].getDataType();
463: break;
464: }
465: }
466: }
467: return result;
468: }
469:
470: public static int[] getColumnTypes(ISQLConnection con,
471: ITableInfo ti, String[] colNames) throws SQLException {
472: TableColumnInfo[] tciArr = con.getSQLMetaData().getColumnInfo(
473: ti);
474: int[] result = new int[tciArr.length];
475: for (int i = 0; i < tciArr.length; i++) {
476: boolean found = false;
477: for (int j = 0; j < colNames.length && !found; j++) {
478: String columnName = colNames[j];
479: if (tciArr[i].getColumnName().equalsIgnoreCase(
480: columnName)) {
481: result[i] = tciArr[i].getDataType();
482: found = true;
483: }
484: }
485: }
486: return result;
487: }
488:
489: public static boolean tableHasPrimaryKey(ISQLConnection con,
490: ITableInfo ti) throws SQLException {
491: boolean result = false;
492: ResultSet rs = null;
493: try {
494: DatabaseMetaData md = con.getConnection().getMetaData();
495: String cat = ti.getCatalogName();
496: String schema = ti.getSchemaName();
497: String tableName = ti.getSimpleName();
498: rs = md.getPrimaryKeys(cat, schema, tableName);
499: if (rs.next()) {
500: result = true;
501: }
502: } finally {
503: closeResultSet(rs);
504: }
505: return result;
506: }
507:
508: /**
509: *
510: * @param con
511: * @param ti
512: * @return
513: * @throws SQLException
514: */
515: public static String getColumnList(TableColumnInfo[] colInfoArr)
516: throws SQLException {
517: StringBuffer result = new StringBuffer();
518:
519: for (int i = 0; i < colInfoArr.length; i++) {
520: TableColumnInfo colInfo = colInfoArr[i];
521: String columnName = colInfo.getColumnName();
522: result.append(columnName);
523: if (i < colInfoArr.length - 1) {
524: result.append(", ");
525: }
526: }
527: return result.toString();
528: }
529:
530: /**
531: *
532: * @param sourceConn
533: * @param ti
534: * @param column
535: * @return
536: * @throws SQLException
537: */
538: public static String getColumnName(ISQLConnection sourceConn,
539: ITableInfo ti, int column) throws SQLException {
540: TableColumnInfo[] infoArr = sourceConn.getSQLMetaData()
541: .getColumnInfo(ti);
542: TableColumnInfo colInfo = infoArr[column];
543: return colInfo.getColumnName();
544: }
545:
546: /**
547: *
548: * @param sourceConn
549: * @param ti
550: * @return
551: * @throws SQLException
552: */
553: public static String[] getColumnNames(ISQLConnection sourceConn,
554: ITableInfo ti) throws SQLException {
555: TableColumnInfo[] infoArr = sourceConn.getSQLMetaData()
556: .getColumnInfo(ti);
557: String[] result = new String[infoArr.length];
558: for (int i = 0; i < result.length; i++) {
559: TableColumnInfo colInfo = infoArr[i];
560: result[i] = colInfo.getColumnName();
561: }
562: return result;
563: }
564:
565: /**
566: *
567: * @param columnList
568: * @param ti
569: * @return
570: * @throws SQLException
571: */
572: public static String getSelectQuery(SessionInfoProvider prov,
573: String columnList, ITableInfo ti) throws SQLException,
574: UserCancelledOperationException {
575: StringBuffer result = new StringBuffer("select ");
576: result.append(columnList);
577: result.append(" from ");
578: ISession sourceSession = prov.getDiffSourceSession();
579:
580: //String sourceSchema = null;
581: // MySQL uses catalogs instead of schemas
582: /*
583: if (DialectFactory.isMySQLSession(sourceSession)) {
584: if (log.isDebugEnabled()) {
585: String catalog =
586: prov.getSourceSelectedDatabaseObjects()[0].getCatalogName();
587: String schema =
588: prov.getSourceSelectedDatabaseObjects()[0].getSchemaName();
589: log.debug("Detected MySQL, using catalog ("+catalog+") " +
590: "instead of schema ("+schema+")");
591: }
592: sourceSchema =
593: prov.getSourceSelectedDatabaseObjects()[0].getCatalogName();
594: } else {
595: sourceSchema =
596: prov.getSourceSelectedDatabaseObjects()[0].getSchemaName();
597: }
598: */
599: String tableName = getQualifiedObjectName(sourceSession, ti
600: .getCatalogName(), ti.getSchemaName(), ti
601: .getSimpleName(), DialectFactory.SOURCE_TYPE);
602: result.append(tableName);
603: return result.toString();
604: }
605:
606: /**
607: * Returns a boolean value indicating whether or not the specified
608: * TableColumnInfo represents a database column that holds binary type
609: * data.
610: *
611: * @param columnInfo the TableColumnInfo to examine
612: * @return true if binary; false otherwise.
613: */
614: public static boolean isBinaryType(TableColumnInfo columnInfo) {
615: boolean result = false;
616: int type = columnInfo.getDataType();
617: if (type == Types.BINARY || type == Types.BLOB
618: || type == Types.LONGVARBINARY
619: || type == Types.VARBINARY) {
620: result = true;
621: }
622: return result;
623: }
624:
625: /**
626: * Decide whether or not the session specified needs fully qualified table
627: * names (schema.table). In most databases this is optional (Oracle).
628: * In others it is required (Progress). In still others it must not occur.
629: * (Axion, Hypersonic)
630: *
631: * @param session
632: * @param catalogName
633: * @param schemaName
634: * @param objectName
635: * @return
636: * @throws UserCancelledOperationException
637: */
638: public static String getQualifiedObjectName(ISession session,
639: String catalogName, String schemaName, String objectName,
640: int sessionType) throws UserCancelledOperationException {
641: String catalog = fixCase(session, catalogName);
642: String schema = fixCase(session, schemaName);
643: String object = fixCase(session, objectName);
644: SQLDatabaseMetaData md = session.getSQLConnection()
645: .getSQLMetaData();
646: boolean useSchema = true;
647: boolean useCatalog = true;
648: try {
649: useCatalog = md.supportsCatalogsInTableDefinitions();
650: } catch (SQLException e) {
651: log
652: .info("Encountered unexpected exception while attempting to "
653: + "determine if catalogs are used in table definitions");
654: }
655: try {
656: useSchema = md.supportsSchemasInTableDefinitions();
657: } catch (SQLException e) {
658: log
659: .info("Encountered unexpected exception while attempting to "
660: + "determine if schemas are used in table definitions");
661: }
662: if (!useCatalog && !useSchema) {
663: return object;
664: }
665: if ((catalog == null || catalog.equals(""))
666: && (schema == null || schema.equals(""))) {
667: return object;
668: }
669: StringBuffer result = new StringBuffer();
670: if (useCatalog && catalog != null && !catalog.equals("")) {
671: result.append(catalog);
672: result.append(getCatSep(session));
673: }
674: if (useSchema && schema != null && !schema.equals("")) {
675: result.append(schema);
676: result.append(".");
677: }
678: result.append(object);
679: return result.toString();
680: }
681:
682: public static String getCatSep(ISession session) {
683: String catsep = ".";
684: try {
685: SQLDatabaseMetaData md = session.getSQLConnection()
686: .getSQLMetaData();
687: catsep = md.getCatalogSeparator();
688: } catch (SQLException e) {
689: log.error("getCatSep: Unexpected Exception - "
690: + e.getMessage(), e);
691: }
692: return catsep;
693: }
694:
695: /**
696: * Uppercase / Lowercase / Mixedcase identifiers are a big problem. Some
697: * databases support mixing case (like McKoi) others force identifier case
698: * to all uppercase or all lowercase. Some (like MySQL) can be configured
699: * to care or not care about case as well as depending on the platform the
700: * database is on. This method attempt to use the metadata from the driver
701: * to "fix" the case of the identifier to be acceptable for the specified
702: * session.
703: *
704: * @param session the session whose disposition on case we care about.
705: * @param identifier
706: * @return
707: */
708: public static String fixCase(ISession session, String identifier) {
709: if (identifier == null || identifier.equals("")) {
710: return identifier;
711: }
712: try {
713: DatabaseMetaData md = session.getSQLConnection()
714: .getConnection().getMetaData();
715:
716: // Don't change the case of the identifier if database allows mixed
717: // case.
718: if (md.storesMixedCaseIdentifiers()) {
719: return identifier;
720: }
721: // Fix the case according to what the database tells us.
722: if (md.storesUpperCaseIdentifiers()) {
723: return identifier.toUpperCase();
724: } else {
725: return identifier.toLowerCase();
726: }
727: } catch (SQLException e) {
728: if (log.isDebugEnabled()) {
729: log.debug("fixCase: unexpected exception: "
730: + e.getMessage());
731: }
732: return identifier;
733: }
734: }
735:
736: /**
737: *
738: * @param sourceConn
739: * @param ti
740: * @return
741: * @throws SQLException
742: */
743: public static int getColumnCount(ISQLConnection sourceConn,
744: ITableInfo ti) throws SQLException {
745: return sourceConn.getSQLMetaData().getColumnInfo(ti).length;
746: }
747:
748: /**
749: *
750: * @param con
751: * @param ti
752: * @param column
753: * @return
754: * @throws SQLException
755: */
756: public static int getColumnType(ISQLConnection con, ITableInfo ti,
757: int column) throws SQLException {
758: TableColumnInfo[] infoArr = con.getSQLMetaData().getColumnInfo(
759: ti);
760: TableColumnInfo colInfo = infoArr[column];
761: return colInfo.getDataType();
762: }
763:
764: public static int[] getColumnTypes(ISQLConnection con, ITableInfo ti)
765: throws SQLException {
766: TableColumnInfo[] infoArr = con.getSQLMetaData().getColumnInfo(
767: ti);
768: int[] result = new int[infoArr.length];
769: for (int i = 0; i < result.length; i++) {
770: TableColumnInfo colInfo = infoArr[i];
771: result[i] = colInfo.getDataType();
772: }
773: return result;
774: }
775:
776: public static boolean sameDatabaseType(ISession session1,
777: ISession session2) {
778: boolean result = false;
779: String driver1ClassName = session1.getDriver()
780: .getDriverClassName();
781: String driver2ClassName = session2.getDriver()
782: .getDriverClassName();
783: if (driver1ClassName.equals(driver2ClassName)) {
784: result = true;
785: }
786: return result;
787: }
788:
789: /**
790: * Gets the SQL statement which can be used to select the maximum length
791: * of the current data found in tableName within the specified column.
792: *
793: * @param sourceSession
794: * @param colInfo
795: * @param tableName
796: * @param tableNameIsQualified TODO
797: * @return
798: */
799: public static String getMaxColumnLengthSQL(ISession sourceSession,
800: TableColumnInfo colInfo, String tableName,
801: boolean tableNameIsQualified)
802: throws UserCancelledOperationException {
803: StringBuffer result = new StringBuffer();
804: HibernateDialect dialect = DialectFactory.getDialect(
805: DialectFactory.SOURCE_TYPE, sourceSession
806: .getApplication().getMainFrame(), sourceSession
807: .getMetaData());
808: String lengthFunction = dialect.getLengthFunction(colInfo
809: .getDataType());
810: if (lengthFunction == null) {
811: log
812: .error("Length function is null for dialect="
813: + dialect.getClass().getName()
814: + ". Using 'length'");
815: lengthFunction = "length";
816: }
817: String maxFunction = dialect.getMaxFunction();
818: if (maxFunction == null) {
819: log.error("Max function is null for dialect="
820: + dialect.getClass().getName() + ". Using 'max'");
821: maxFunction = "max";
822: }
823: result.append("select ");
824: result.append(maxFunction);
825: result.append("(");
826: result.append(lengthFunction);
827: result.append("(");
828: result.append(colInfo.getColumnName());
829: result.append(")) from ");
830: String table = tableName;
831: if (!tableNameIsQualified) {
832: table = getQualifiedObjectName(sourceSession, colInfo
833: .getCatalogName(), colInfo.getSchemaName(),
834: tableName, DialectFactory.SOURCE_TYPE);
835: }
836: result.append(table);
837: return result.toString();
838: }
839:
840: /**
841: * @param lastStatement the lastStatement to set
842: */
843: public static void setLastStatement(String lastStatement) {
844: DBUtil.lastStatement = lastStatement;
845: }
846:
847: /**
848: * @return the lastStatement
849: */
850: public static String getLastStatement() {
851: return lastStatement;
852: }
853:
854: public static void setLastStatementValues(String values) {
855: lastStatementValues = values;
856: }
857:
858: public static String getLastStatementValues() {
859: return lastStatementValues;
860: }
861: }
|