Quadcap Embeddable Database

com/quadcap/sql/tools/XmlDump.java

Go to the documentation of this file.
00001 package com.quadcap.sql.tools; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.BufferedWriter; 00042 import java.io.FileInputStream; 00043 import java.io.FileOutputStream; 00044 import java.io.IOException; 00045 import java.io.InputStream; 00046 import java.io.OutputStream; 00047 import java.io.OutputStreamWriter; 00048 import java.io.Reader; 00049 import java.io.Writer; 00050 00051 00052 import java.util.Iterator; 00053 import java.util.List; 00054 import java.util.HashMap; 00055 import java.util.Map; 00056 00057 00058 import java.util.ArrayList; 00059 import java.util.Hashtable; 00060 import java.util.Properties; 00061 import java.util.Vector; 00062 00063 import java.sql.Blob; 00064 import java.sql.Clob; 00065 import java.sql.Connection; 00066 import java.sql.DatabaseMetaData; 00067 import java.sql.ResultSet; 00068 import java.sql.ResultSetMetaData; 00069 import java.sql.Statement; 00070 00071 import java.sql.SQLException; 00072 import java.sql.Types; 00073 00074 import java.util.zip.GZIPOutputStream; 00075 00076 import com.quadcap.sql.Backup; 00077 00078 import com.quadcap.sql.types.Type; 00079 00080 import com.quadcap.util.Config; 00081 import com.quadcap.util.Debug; 00082 00083 import com.quadcap.util.collections.DiGraph; 00084 00085 /** 00086 * Dump an SQL database in an XML representation. The XML document 00087 * has an outer tag of <code>&lt;database&gt;</code>. Each child element 00088 * then contains one table row, where the tag name specifies the table name; 00089 * each child element of this tag contains one column value where the 00090 * tag name specifies the column name. Most object are represented in 00091 * their standard Java <code>toString</code> style representation, except 00092 * binary objects, which are dumped in hexadecimal. (Base-64 would probably 00093 * be better...) 00094 * 00095 * @author Stan Bailes 00096 */ 00097 00098 public class XmlDump implements Backup { 00099 Connection conn; 00100 int indentLevel = 0; 00101 String lineSep; 00102 boolean wasBegin = false; 00103 boolean wasEnd = false; 00104 00105 /** 00106 * No-argument constructor. The object so constructed needs a 00107 * <code>Connection</code> in order to do anything useful. 00108 */ 00109 public XmlDump() { 00110 lineSep = System.getProperty("line.separator"); 00111 } 00112 00113 /** 00114 * Construct an XmlDump object bound to the specified connection. 00115 * 00116 * @param conn the database connection 00117 */ 00118 public XmlDump(Connection conn) { 00119 this.conn = conn; 00120 lineSep = System.getProperty("line.separator"); 00121 } 00122 00123 /** 00124 * Construct an XmlDump object bound to the specified connection, 00125 * and with a specified initial indent level. 00126 * 00127 * @param conn the database connection 00128 * @param indentLevel the initial indent level (in units -- currently 00129 * indent units are simple spaces 00130 */ 00131 public XmlDump(Connection conn, int indentLevel) { 00132 this.indentLevel = indentLevel; 00133 this.conn = conn; 00134 lineSep = System.getProperty("line.separator"); 00135 } 00136 00137 /** 00138 * Set the dumper's database connection 00139 * 00140 * @param conn the new database connection 00141 */ 00142 public void setConnection(Connection conn) { 00143 this.conn = conn; 00144 } 00145 00146 /** 00147 * Get the dumper's database connection 00148 * 00149 * @return the current database connection 00150 */ 00151 public Connection getConnection() { 00152 return conn; 00153 } 00154 00155 final void beginTag(Writer w, String tag) throws IOException { 00156 if (wasBegin) w.write(lineSep); 00157 for (int i = 0; i < indentLevel; i++) w.write(' '); 00158 indentLevel++; 00159 w.write('<'); 00160 w.write(tag); 00161 w.write('>'); 00162 wasBegin = true; 00163 wasEnd = false; 00164 } 00165 00166 final void endTag(Writer w, String tag) throws IOException { 00167 indentLevel--; 00168 if (wasEnd) { 00169 for (int i = 0; i < indentLevel; i++) w.write(' '); 00170 } 00171 w.write('<'); 00172 w.write('/'); 00173 w.write(tag); 00174 w.write('>'); 00175 w.write(lineSep); 00176 wasBegin = false; 00177 wasEnd = true; 00178 } 00179 00180 static final String charsLt = "&lt;"; 00181 static final String charsGt = "&gt;"; 00182 static final String charsAmp = "&amp;"; 00183 00184 final void writeString(Writer w, String str) throws IOException { 00185 for (int i = 0; i < str.length(); i++) { 00186 char c = str.charAt(i); 00187 switch (c) { 00188 case '<': 00189 w.write(charsLt); 00190 break; 00191 case '>': 00192 w.write(charsGt); 00193 break; 00194 case '&': 00195 w.write(charsAmp); 00196 break; 00197 default: 00198 w.write(c); 00199 } 00200 } 00201 wasBegin = false; 00202 wasEnd = false; 00203 } 00204 00205 static final char[] hexBytes = { 00206 '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' 00207 }; 00208 00209 final void writeBinaryStream(Writer w, InputStream is) throws IOException { 00210 int c; 00211 while ((c = is.read()) >= 0) { 00212 w.write(hexBytes[(c >> 4) & 0xf]); 00213 w.write(hexBytes[c & 0xf]); 00214 } 00215 } 00216 00217 final void writeCharacterStream(Writer w, Reader r) throws IOException { 00218 int ci; 00219 while ((ci = r.read()) >= 0) { 00220 char c = (char)ci; 00221 switch (c) { 00222 case '<': 00223 w.write(charsLt); 00224 break; 00225 case '>': 00226 w.write(charsGt); 00227 break; 00228 case '&': 00229 w.write(charsAmp); 00230 break; 00231 default: 00232 w.write(c); 00233 } 00234 } 00235 } 00236 00237 final void writeBinary(Writer w, Object obj) 00238 throws IOException 00239 { 00240 if (obj instanceof Boolean) { 00241 w.write((((Boolean)obj).booleanValue()) ? '1' : '0'); 00242 } else { 00243 byte[] buf = (byte[])obj; 00244 for (int i = 0; i < buf.length; i++) { 00245 byte c = buf[i]; 00246 w.write(hexBytes[(c >> 4) & 0xf]); 00247 w.write(hexBytes[c & 0xf]); 00248 } 00249 } 00250 } 00251 00252 final void writeValue(Writer w, Object obj, int jdbcType) 00253 throws SQLException, IOException 00254 { 00255 switch (jdbcType) { 00256 case Types.BIT: 00257 case Types.TINYINT: 00258 case Types.SMALLINT: 00259 case Types.INTEGER: 00260 case Types.BIGINT: 00261 case Types.FLOAT: 00262 case Types.REAL: 00263 case Types.DOUBLE: 00264 case Types.NUMERIC: 00265 case Types.DECIMAL: 00266 case Types.CHAR: 00267 case Types.VARCHAR: 00268 case Types.LONGVARCHAR: 00269 case Types.DATE: 00270 case Types.TIME: 00271 case Types.TIMESTAMP: 00272 case Types.OTHER: 00273 writeString(w, obj.toString()); 00274 break; 00275 //- //#ifdef JDK11 00276 //- case Type.CLOB: 00277 //#else 00278 case Types.CLOB: 00279 writeCharacterStream(w, ((Clob)obj).getCharacterStream()); 00280 //#endif 00281 break; 00282 //- //#ifdef JDK11 00283 //- case Type.BLOB: 00284 //#else 00285 case Types.BLOB: 00286 //#endif 00287 writeBinaryStream(w, ((Blob)obj).getBinaryStream()); 00288 break; 00289 case Types.BINARY: 00290 case Types.VARBINARY: 00291 case Types.LONGVARBINARY: 00292 writeBinary(w, obj); 00293 break; 00294 case Types.NULL: 00295 //#ifndef JDK11 00296 case Types.JAVA_OBJECT: 00297 case Types.DISTINCT: 00298 case Types.STRUCT: 00299 case Types.ARRAY: 00300 case Types.REF: 00301 //#endif 00302 throw new IOException("Not supported, jdbc type: " + jdbcType + 00303 ", object = " + obj.getClass().getName() + ": " + obj); 00304 } 00305 } 00306 00307 List parseViewDef(String s) { 00308 List ret = new ArrayList(); 00309 StringBuffer sb = new StringBuffer(); 00310 int idx = s.indexOf(" AS "); 00311 if (idx >= 0) { 00312 s = s.substring(idx+4); 00313 } 00314 boolean l = false; 00315 for (int i = 0; i < s.length(); i++) { 00316 char c = s.charAt(i); 00317 boolean d = Character.isLetterOrDigit(c) || c == '.'; 00318 if (d ^ l) { 00319 if (sb.length() > 0) { 00320 ret.add(sb.toString()); 00321 sb.setLength(0); 00322 } 00323 } 00324 if (d) { 00325 sb.append(c); 00326 } 00327 l = d; 00328 } 00329 if (sb.length() > 0) ret.add(sb.toString()); 00330 return ret; 00331 } 00332 00333 void dumpViewDefinitions(Writer w) throws SQLException, IOException { 00334 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00335 ResultSet rs = (ResultSet)dbMeta.getTables(null, "%", "%", null); 00336 Map map = new HashMap(); 00337 DiGraph graph = new DiGraph(); 00338 try { 00339 while (rs.next()) { 00340 String type = rs.getString(4); 00341 if (type.toLowerCase().indexOf("view") >= 0) { 00342 String schema = rs.getString(2); 00343 String table = rs.getString(3); 00344 if (schema != null && schema.length() > 0) { 00345 table = schema + "." + table; 00346 } 00347 String view = rs.getString(5); 00348 if (view != null) { 00349 Iterator it = parseViewDef(view).iterator(); 00350 while (it.hasNext()) { 00351 String base = it.next().toString(); 00352 graph.addArc(base, table); 00353 //graph.addArc(table, base); 00354 } 00355 map.put(table, view); 00356 } 00357 } 00358 } 00359 Iterator iter = graph.levelize(true); 00360 while (iter.hasNext()) { 00361 String s = iter.next().toString(); 00362 Object x = map.get(s); 00363 if (x != null) { 00364 beginTag(w, "ddl"); 00365 writeString(w, "CREATE " + x.toString()); 00366 endTag(w, "ddl"); 00367 } 00368 } 00369 } finally { 00370 rs.close(); 00371 } 00372 } 00373 00374 void dumpIndexDefinitions(Writer w, String tableName) 00375 throws SQLException, IOException 00376 { 00377 String schemaP = null; 00378 String tableP = tableName; 00379 int idx = tableName.indexOf('.'); 00380 if (idx > 0) { 00381 schemaP = tableName.substring(0, idx); 00382 tableP = tableName.substring(idx+1); 00383 } 00384 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00385 ResultSet rs = (ResultSet)dbMeta.getIndexInfo(null, schemaP, tableP, false, true); 00386 try { 00387 StringBuffer columns = new StringBuffer(); 00388 boolean unique = false; 00389 String table = null; 00390 String index = null; 00391 while (rs.next()) { 00392 if (rs.getObject(5) != null) { 00393 String sch = rs.getString(2); 00394 String tab = rs.getString(3); 00395 if (sch != null && sch.length() > 0) { 00396 tab = sch + "." + tab; 00397 } 00398 if (index != null && !index.equals(rs.getString(6))) { 00399 beginTag(w, "ddl"); 00400 writeString(w, "CREATE " + (unique ? "UNIQUE " : "") + 00401 " INDEX " + index + " ON " + 00402 table + "(" + columns + ")"); 00403 endTag(w, "ddl"); 00404 columns.setLength(0); 00405 } 00406 String column = rs.getString(9); 00407 unique = !rs.getBoolean(4); 00408 index = rs.getString(6); 00409 table = tab; 00410 if (columns.length() > 0) columns.append(", "); 00411 columns.append(column); 00412 } 00413 } 00414 if (index != null) { 00415 beginTag(w, "ddl"); 00416 writeString(w, "CREATE " + (unique ? "UNIQUE " : "") + 00417 " INDEX " + index + " ON " + 00418 table + "(" + columns + ")"); 00419 endTag(w, "ddl"); 00420 } 00421 } finally { 00422 rs.close(); 00423 } 00424 } 00425 00426 00427 final Iterator orderTables() throws SQLException { 00428 ArrayList t = new ArrayList(); 00429 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00430 ResultSet rs = (ResultSet)dbMeta.getTables(null, "%", "%", null); 00431 try { 00432 while (rs.next()) { 00433 String type = rs.getString(4); 00434 if (type.toLowerCase().indexOf("table") >= 0) { 00435 String schema = rs.getString(2); 00436 String table = rs.getString(3); 00437 if (schema != null && schema.length() > 0) { 00438 table = schema + "." + table; 00439 } 00440 t.add(table); 00441 } 00442 } 00443 } finally { 00444 rs.close(); 00445 } 00446 return t.iterator(); 00447 } 00448 00449 class DbType { 00450 int type; 00451 String prefix; 00452 String suffix; 00453 String createParams; 00454 DbType(int type, String prefix, String suffix, String createParams) { 00455 this.type = type; 00456 this.prefix = prefix == null ? "" : prefix; 00457 this.suffix = suffix == null ? "" : suffix; 00458 this.createParams = createParams == null ? "" : createParams; 00459 } 00460 00461 String getTypePrefix() { return prefix; } 00462 String getTypeSuffix() { return suffix; } 00463 00464 String getCreateParams(ResultSet rs) throws SQLException { 00465 StringBuffer sb = new StringBuffer(""); 00466 String cp = createParams; 00467 while (cp.length() > 0) { 00468 String param = cp; 00469 int idx = cp.indexOf(','); 00470 if (idx > 0) { 00471 param = cp.substring(0, idx).trim(); 00472 cp = cp.substring(idx+1).trim(); 00473 } else { 00474 cp = ""; 00475 } 00476 if (param.equalsIgnoreCase("length") || 00477 param.equalsIgnoreCase("precision")) { 00478 if (sb.length() == 0) { 00479 sb.append('('); 00480 } else { 00481 sb.append(','); 00482 } 00483 sb.append(rs.getString(7)); 00484 } else if (param.equalsIgnoreCase("scale")) { 00485 if (sb.length() == 0) { 00486 sb.append('('); 00487 } else { 00488 sb.append(','); 00489 } 00490 sb.append(rs.getString(9)); 00491 } 00492 } 00493 if (sb.length() > 0) { 00494 sb.append(')'); 00495 } 00496 return sb.toString(); 00497 } 00498 }; 00499 00500 Hashtable types = null; 00501 00502 Hashtable getTypes() throws SQLException { 00503 if (types == null) { 00504 types = new Hashtable(); 00505 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00506 ResultSet rs = (ResultSet)dbMeta.getTypeInfo(); 00507 while (rs.next()) { 00508 int type = rs.getInt(2); 00509 String prefix = rs.getString(4); 00510 String suffix = rs.getString(5); 00511 String createParams = rs.getString(6); 00512 DbType t = new DbType(type, prefix, suffix, createParams); 00513 types.put(new Integer(type), t); 00514 } 00515 } 00516 return types; 00517 } 00518 00519 DbType getType(int type) throws SQLException { 00520 DbType t = null; 00521 getTypes(); 00522 t = (DbType)types.get(new Integer(type)); 00523 if (t == null) { 00524 throw new RuntimeException("no type: " + type); 00525 } 00526 return t; 00527 } 00528 00529 /** 00530 * Dump the SQL foreign key constraints for the specified table 00531 */ 00532 public void dumpTableForeignKeys(Writer w, String tableName) 00533 throws SQLException, IOException 00534 { 00535 String schema = null; 00536 String table = tableName; 00537 int idx = tableName.indexOf('.'); 00538 if (idx > 0) { 00539 schema = tableName.substring(0, idx); 00540 table = tableName.substring(idx+1); 00541 } 00542 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00543 ResultSet rs = (ResultSet)dbMeta.getImportedKeys(null, schema, table); 00544 String cname = ""; 00545 Vector pkeys = null; 00546 String pkTable = null; 00547 StringBuffer sb = new StringBuffer(""); 00548 while (rs.next()) { 00549 String constraintName = rs.getString(12); 00550 if (!constraintName.equals(cname)) { 00551 if (cname.length() > 0) { 00552 sb.append(") references "); 00553 sb.append(pkTable); 00554 sb.append("("); 00555 for (int i = 0; i < pkeys.size(); i++) { 00556 if (i > 0) sb.append(", "); 00557 sb.append(pkeys.elementAt(i).toString()); 00558 } 00559 sb.append(")\n"); 00560 beginTag(w, "ddl"); 00561 writeString(w, sb.toString()); 00562 endTag(w, "ddl"); 00563 } 00564 String pkSchema = rs.getString(2); 00565 if (pkSchema != null && pkSchema.length() > 0) { 00566 pkTable = pkSchema + "." + rs.getString(3); 00567 } else { 00568 pkTable = rs.getString(3); 00569 } 00570 cname = constraintName; 00571 sb.setLength(0); 00572 sb.append("\nalter table "); 00573 sb.append(tableName); 00574 sb.append(" add constraint "); 00575 sb.append(cname); 00576 sb.append(" foreign key("); 00577 pkeys = new Vector(); 00578 } else { 00579 sb.append(", "); 00580 } 00581 sb.append(rs.getString(8)); 00582 pkeys.addElement(rs.getString(4)); 00583 } 00584 if (cname.length() > 0) { 00585 sb.append(") references "); 00586 sb.append(pkTable); 00587 sb.append("("); 00588 for (int i = 0; i < pkeys.size(); i++) { 00589 if (i > 0) sb.append(", "); 00590 sb.append(pkeys.elementAt(i).toString()); 00591 } 00592 sb.append(")"); 00593 beginTag(w, "ddl"); 00594 writeString(w, sb.toString()); 00595 endTag(w, "ddl"); 00596 } 00597 } 00598 00599 /** 00600 * Dump the SQL table definition for the specified table 00601 */ 00602 public void dumpTableDefinition(Writer w, String tableName) 00603 throws SQLException, IOException 00604 { 00605 Hashtable constraints = new Hashtable(); 00606 String schema = null; 00607 String table = tableName; 00608 int idx = tableName.indexOf('.'); 00609 if (idx > 0) { 00610 schema = tableName.substring(0, idx); 00611 table = tableName.substring(idx+1); 00612 } 00613 DatabaseMetaData dbMeta = (DatabaseMetaData)conn.getMetaData(); 00614 ResultSet rs = (ResultSet)dbMeta.getColumns(null, schema, table, "%"); 00615 00616 ResultSet rs2 = 00617 conn.createStatement().executeQuery("select * from " + tableName); 00618 ResultSetMetaData rsMeta = rs2.getMetaData(); 00619 00620 StringBuffer sb = new StringBuffer("\ncreate table "); 00621 sb.append(tableName); 00622 sb.append('('); 00623 boolean first = true; 00624 while (rs.next()) { 00625 sb.append("\n\t"); 00626 if (!first) sb.append(", "); 00627 first = false; 00628 int type = rs.getInt(5); 00629 DbType t = getType(type); 00630 sb.append(rs.getString(4)); // column name 00631 sb.append(' '); 00632 sb.append(rs.getString(6)); // type name 00633 sb.append(t.getCreateParams(rs)); 00634 if (rs.getInt(11) == ResultSetMetaData.columnNoNulls) { 00635 sb.append(" NOT NULL"); 00636 } 00637 String dflt = rs.getString(13); 00638 if (dflt != null) { 00639 sb.append(" DEFAULT "); 00640 sb.append(t.getTypePrefix()); 00641 sb.append(dflt); 00642 sb.append(t.getTypeSuffix()); 00643 } 00644 if (rsMeta.isAutoIncrement(rs.getInt(17))) { 00645 sb.append(" WITH IDENTITY"); 00646 } 00647 } 00648 rs.close(); 00649 rs2.close(); 00650 00651 rs = (ResultSet)dbMeta.getPrimaryKeys(null, schema, table); 00652 first = true; 00653 while (rs.next()) { 00654 if (first) { 00655 constraints.put(rs.getString(6), ""); 00656 sb.append("\n\t, constraint "); 00657 sb.append(rs.getString(6)); // constraint name 00658 sb.append(" primary key ("); 00659 first = false; 00660 } else { 00661 sb.append(", "); 00662 } 00663 sb.append(rs.getString(4)); // column name 00664 } 00665 if (!first) sb.append(')'); 00666 rs.close(); 00667 00668 String iname = ""; 00669 rs = (ResultSet)dbMeta.getIndexInfo(null, schema, table, true, false); 00670 first = true; 00671 while (rs.next()) { 00672 String indexName = rs.getString(6); 00673 if (constraints.get(indexName) != null) continue; 00674 if (rs.getObject(5) != null) continue; 00675 if (indexName.equals(iname)) { 00676 sb.append(", "); 00677 } else { 00678 if (iname.length() > 0) { 00679 sb.append(")"); 00680 } 00681 sb.append("\n\t, constraint "); 00682 sb.append(indexName); 00683 sb.append(" unique("); 00684 iname = indexName; 00685 } 00686 sb.append(rs.getString(9)); // column name 00687 } 00688 if (iname.length() > 0) { 00689 sb.append(')'); 00690 } 00691 rs.close(); 00692 00693 sb.append(")\n"); 00694 beginTag(w, "ddl"); 00695 writeString(w, sb.toString()); 00696 endTag(w, "ddl"); 00697 } 00698 00699 /** 00700 * Dump the rows of the specified table to the output stream in XML 00701 * format. Each row is dumped as an XML element with the tag name 00702 * equal to the table name. Each non-null column is dumped as a 00703 * sub-element with the tag name equal to the column name. 00704 * 00705 * @param w the output stream 00706 * @param tableName the name of the database table to dump. 00707 * 00708 * @exception IOException may be thrown 00709 * @exception SQLException may be thrown 00710 */ 00711 public void dumpTable(Writer w, String tableName) 00712 throws IOException, SQLException 00713 { 00714 tableName = tableName.toUpperCase(); 00715 Statement s = (Statement)conn.createStatement(); 00716 try { 00717 ResultSet rs = (ResultSet)s.executeQuery("select * from " + tableName); 00718 try { 00719 ResultSetMetaData rm = (ResultSetMetaData)rs.getMetaData(); 00720 int cols = rm.getColumnCount(); 00721 while (rs.next()) { 00722 beginTag(w, tableName); 00723 for (int i = 1; i <= cols; i++) { 00724 Object obj = rs.getObject(i); 00725 if (!rs.wasNull()) { 00726 beginTag(w, rm.getColumnName(i)); 00727 try { 00728 writeValue(w, obj, rm.getColumnType(i)); 00729 } catch (IOException e) { 00730 Debug.println("Table: " + tableName + 00731 ", column = " + i + ": " + 00732 rm.getColumnName(i)); 00733 throw e; 00734 } 00735 endTag(w, rm.getColumnName(i)); 00736 } 00737 } 00738 endTag(w, tableName); 00739 } 00740 } finally { 00741 rs.close(); 00742 } 00743 } finally { 00744 s.close(); 00745 } 00746 } 00747 00748 /** 00749 * Dump all of the tables in the database which is referenced by the 00750 * current connection object to the specified output stream. This 00751 * routine writes a well-formed XML document, with a document element 00752 * named <code>&lt;database&gt;</code>. Sub-elements correspond to 00753 * indidivual table rows.<p> 00754 * 00755 * This routine first constructs a graph of the foreign table reference 00756 * constraints, and attempts to output base tables before dependant 00757 * tables, so that the resulting file can be imported without causing 00758 * foreign key integrity violations.<p> 00759 * 00760 * @param w the output stream 00761 * 00762 * @exception IOException may be thrown 00763 * @exception SQLException may be thrown 00764 */ 00765 public void dumpTables(Writer w) 00766 throws IOException, SQLException 00767 { 00768 w.write("<?xml version=\"1.0\"?>\n"); 00769 beginTag(w, "database"); 00770 Iterator iter = orderTables(); 00771 while (iter.hasNext()) { 00772 String table = iter.next().toString(); 00773 dumpTableDefinition(w, table); 00774 } 00775 dumpViewDefinitions(w); 00776 00777 iter = orderTables(); 00778 beginTag(w, "dml"); 00779 while (iter.hasNext()) { 00780 String table = iter.next().toString(); 00781 dumpTable(w, table); 00782 } 00783 endTag(w, "dml"); 00784 00785 iter = orderTables(); 00786 while (iter.hasNext()) { 00787 String table = iter.next().toString(); 00788 dumpIndexDefinitions(w, table); 00789 } 00790 00791 iter = orderTables(); 00792 while (iter.hasNext()) { 00793 String table = iter.next().toString(); 00794 dumpTableForeignKeys(w, table); 00795 } 00796 endTag(w, "database"); 00797 } 00798 00799 /** 00800 * A convenience function that sets the current connection and dumps 00801 * the database in one go. 00802 * 00803 * @param conn the database connection 00804 * @param w the output stream 00805 * 00806 * @exception IOException may be thrown 00807 * @exception SQLException may be thrown 00808 */ 00809 public void backup(java.sql.Connection conn, Writer w) 00810 throws IOException, SQLException 00811 { 00812 this.conn = (Connection)conn; 00813 dumpTables(w); 00814 } 00815 00816 /** 00817 * Establish a database connection based on the settings of system 00818 * properties. 00819 * 00820 * <p>The following system properties are used to establish the 00821 * database connection: 00822 * <table border=1> 00823 * <tr><th align=left>jdbc.driver</th> 00824 * <td>The name of the JDBC driver class (default 00825 * <code>com.quadcap.jdbc.JdbcDriver</code>)</td></tr> 00826 * <tr><th align=left>jdbc.url</th> 00827 * <td>The JDBC URL used to establish the database connection. 00828 * </td></tr> 00829 * <tr><th align=left>jdbc.props</th> 00830 * <td>The name of a properties file used to establish the connection. 00831 * If this property is specified, <code>jdbc.user</code> and 00832 * <code>jdbc.password</code> aren't used. 00833 * If this property has the value <code>"system"</code>, then 00834 * the system properties are passed to the 00835 * <code>DriverManager.getConnection()</code> method. 00836 * </td></tr> 00837 * <tr><th align=left>jdbc.user</th> 00838 * <td>The user name used to establish the 00839 * database connection. If neither <code>jdbc.props</code> 00840 * nor <code>jdbc.user</code> is specified, the 00841 * <code>DriverManager.getConnection(String url)</code> 00842 * method is used to establish the connection.</td></tr> 00843 * <tr><th align=left>jdbc.password</th> 00844 * <td>The password used to establish the 00845 * database connection.</td></tr> 00846 * </table> 00847 * </p> 00848 * 00849 * @exception Exception may be thrown if there's a problem connecting 00850 * to the database. 00851 */ 00852 public static Connection makeConnection() throws Exception { 00853 Config.reset(); 00854 String driver = Config.getProperty("jdbc.driver", 00855 "com.quadcap.jdbc.JdbcDriver"); 00856 String url = Config.getProperty("jdbc.url"); 00857 String user = Config.getProperty("jdbc.user"); 00858 String pass = Config.getProperty("jdbc.password"); 00859 String propsfile = Config.getProperty("jdbc.props"); 00860 Connection xconn = null; 00861 Class.forName(driver); 00862 if (propsfile != null) { 00863 Properties props; 00864 if (propsfile.equals("system")) { 00865 props = System.getProperties(); 00866 } else { 00867 props = new Properties(); 00868 FileInputStream pfile = new FileInputStream(propsfile); 00869 props.load(pfile); 00870 } 00871 xconn = 00872 (Connection)java.sql.DriverManager.getConnection(url, props); 00873 } else if (user != null) { 00874 xconn = 00875 (Connection)java.sql.DriverManager.getConnection(url, user, 00876 pass); 00877 } else { 00878 xconn = (Connection)java.sql.DriverManager.getConnection(url); 00879 } 00880 return xconn; 00881 } 00882 00883 /** 00884 * A main program which allows this function to be run as a command-line 00885 * application for doing an off-line dump. The name of the output file is 00886 * specified as the argument. If the name of the output file 00887 * ends with <code>".gz"</code>, the output is compressed using the 00888 * <code>gzip</code> compression mechanism. 00889 * 00890 * @see makeConnection for a description of the System properties used 00891 * to establish the database connection. 00892 * @param args <code>com.quadcap.sql.tools.XmlDump</code> 00893 * <i>output file</i> 00894 */ 00895 public static void main(String[] args) { 00896 try { 00897 Connection xconn = makeConnection(); 00898 try { 00899 XmlDump dump = new XmlDump(xconn); 00900 String outfile = args[0]; 00901 if (outfile.endsWith(".xml")) { 00902 FileOutputStream fos = new FileOutputStream(outfile); 00903 OutputStreamWriter ow = new OutputStreamWriter(fos); 00904 BufferedWriter bw = new BufferedWriter(ow); 00905 dump.dumpTables(bw); 00906 bw.close(); 00907 } else if (outfile.endsWith(".xml.gz")) { 00908 FileOutputStream fos = new FileOutputStream(outfile); 00909 GZIPOutputStream gos = new GZIPOutputStream(fos); 00910 OutputStreamWriter ow = new OutputStreamWriter(gos); 00911 BufferedWriter bw = new BufferedWriter(ow); 00912 dump.dumpTables(bw); 00913 bw.flush(); 00914 bw.close(); 00915 } else { 00916 throw new Exception("Unrecognized output type for file: " + 00917 outfile); 00918 } 00919 } finally { 00920 xconn.close(); 00921 } 00922 } catch (Exception e) { 00923 com.quadcap.util.Debug.print(e); 00924 } 00925 } 00926 }