| 
      
      
      From: <fu...@us...> - 2010-01-21 20:31:35
      
     | 
| Revision: 1020
          http://cishell.svn.sourceforge.net/cishell/?rev=1020&view=rev
Author:   fugu13
Date:     2010-01-21 20:31:28 +0000 (Thu, 21 Jan 2010)
Log Message:
-----------
Add various database utilities.
Modified Paths:
--------------
    trunk/core/org.cishell.utilities/META-INF/MANIFEST.MF
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/DatabaseUtilities.java
Added Paths:
-----------
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/Column.java
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ColumnPair.java
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/DatabaseTable.java
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKey.java
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKeyNameWithTable.java
    trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/InvalidRepresentationException.java
Modified: trunk/core/org.cishell.utilities/META-INF/MANIFEST.MF
===================================================================
--- trunk/core/org.cishell.utilities/META-INF/MANIFEST.MF	2010-01-14 21:02:06 UTC (rev 1019)
+++ trunk/core/org.cishell.utilities/META-INF/MANIFEST.MF	2010-01-21 20:31:28 UTC (rev 1020)
@@ -20,6 +20,7 @@
  prefuse.util,
  prefuse.util.collections
 Export-Package: org.cishell.utilities,
+ org.cishell.utilities.database,
  org.cishell.utilities.mutateParameter,
  org.cishell.utilities.mutateParameter.defaultvalue,
  org.cishell.utilities.mutateParameter.dropdown,
Modified: trunk/core/org.cishell.utilities/src/org/cishell/utilities/DatabaseUtilities.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/DatabaseUtilities.java	2010-01-14 21:02:06 UTC (rev 1019)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/DatabaseUtilities.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -2,12 +2,18 @@
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
 
 import org.cishell.framework.algorithm.AlgorithmExecutionException;
 import org.cishell.service.database.Database;
 
 public class DatabaseUtilities {
 	public static void closeConnectionQuietly(Connection connection) {
+		if(connection == null) {
+			return;
+		}
 		try {
 			connection.close();
 		} catch (SQLException e) {
@@ -25,4 +31,38 @@
 		}
 		return connection;
 	}
+	
+	public static String getInExpression(List<String> columns, List<Map<String, Object>> valueMaps) {
+		String columnNames = implodeAndWrap(columns);
+		
+		List<String> values = new ArrayList<String>();
+		for(Map<String, Object> oldValues : valueMaps) {
+			List<String> rowValues = new ArrayList<String>();
+			for(String column : columns) {
+				rowValues.add(formatValue(oldValues.get(column)));
+			}
+			values.add(implodeAndWrap(rowValues));
+		}
+		String columnValues = implodeAndWrap(values);
+		
+		
+		//first make part with column names
+		//then make part with groups of column values
+		return columnNames + " IN " + columnValues;
+	}
+	
+	//TODO: expand this to other sorts of SQL datatypes (per their Prefuse table equivalents)
+	public static String formatValue(Object value) {
+		if(value == null) {
+			return "NULL";
+		} else if(value instanceof Number) {
+			return value.toString();
+		} else {
+			return "'" + value.toString() + "'";
+		}
+	}
+	
+	public static String implodeAndWrap(List<String> values) {
+		return "(" + StringUtilities.implodeList(values, ", ") + ")";
+	}
 }
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/Column.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/Column.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/Column.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,55 @@
+package org.cishell.utilities.database;
+
+import java.sql.Types;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class Column {
+	
+	public final String name;
+	public final int type;
+	public final int size;
+	
+	public static final Map<Integer, String> TYPE_MAP  = constructTypeMap();
+	public static final Set<Integer> SIZED_TYPES = constructSizedTypes();
+	
+	private static Map<Integer, String> constructTypeMap() { //if this ever gets derby specific, it shouldn't go here
+		Map<Integer, String> typeMap = new HashMap<Integer, String>() {{
+			put(Types.CHAR, "char");
+			put(Types.DATE, "date");
+			put(Types.DOUBLE, "double");
+			put(Types.FLOAT, "float");
+			put(Types.INTEGER, "integer");
+			put(Types.SMALLINT, "smallint");
+			put(Types.TIME, "time");
+			put(Types.VARCHAR, "varchar");
+		}};
+		return Collections.unmodifiableMap(typeMap);
+	}
+	
+	private static Set<Integer> constructSizedTypes() {
+		Set<Integer> sizedTypes = new HashSet<Integer>() {{
+			add(Types.CHAR);
+			add(Types.VARCHAR);
+			
+		}};
+		return null;
+	}
+
+	public Column(String name, int type, int size) {
+		this.name = name;
+		this.type = type;
+		this.size = size;
+	}
+
+	
+
+	public String getDefinition() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ColumnPair.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ColumnPair.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ColumnPair.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,23 @@
+package org.cishell.utilities.database;
+
+public final class ColumnPair {
+	public final String local;
+	public final String foreign;
+	
+	public ColumnPair(String local, String foreign) {
+		this.local = local;
+		this.foreign = foreign;
+	}
+	
+	public boolean equals(Object other) {
+		if(!(other instanceof ColumnPair)) {
+			return false;
+		}
+		ColumnPair o = (ColumnPair) other;
+		return o.local.equals(this.local) && o.foreign.equals(this.foreign);
+	}
+	
+	public int hashCode() {
+		return local.hashCode() * 31 + foreign.hashCode();
+	}
+}
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/DatabaseTable.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/DatabaseTable.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/DatabaseTable.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,193 @@
+package org.cishell.utilities.database;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.cishell.utilities.DatabaseUtilities;
+
+public final class DatabaseTable {
+	public final String catalog;
+	public final String schema;
+	public final String name;
+
+	public DatabaseTable(String catalog, String schema, String name) {
+		this.catalog = catalog == null ? "" : catalog.intern();
+		this.schema = schema == null ? "" : schema.intern();
+		this.name = name == null ? "" : name.intern();
+	}
+	
+	public static DatabaseTable fromRepresentation(String representation) throws InvalidRepresentationException {
+		String[] parts = representation.split("\\.");
+		switch(parts.length) {
+			case 1:
+				return new DatabaseTable(null, null, parts[0]);
+			case 2:
+				return new DatabaseTable(null, parts[0], parts[1]);
+			case 3:
+				return new DatabaseTable(parts[0], parts[1], parts[2]);
+			default:
+				throw new InvalidRepresentationException("The representation '" + representation + "' has the wrong number of parts!");
+		}
+	}
+	
+	public static DatabaseTable[] availableTables(Connection connection) throws SQLException {
+		ResultSet results = connection.getMetaData().getTables(null, null, null, new String[]{"TABLE"});
+		
+		List<DatabaseTable> tables = new ArrayList<DatabaseTable>();
+		while(results.next()) {
+			tables.add(new DatabaseTable(results.getString(1), results.getString(2), results.getString(3)));
+		}
+		
+		results.close();
+		
+		return tables.toArray(new DatabaseTable[]{});
+	}
+	
+	public String toString() {
+		StringBuilder output = new StringBuilder();
+		if(catalog != null && catalog != "") {
+			output.append(catalog);
+			output.append('.');
+		}
+		if(schema != null && schema != "") {
+			output.append(schema);
+			output.append('.');
+		}
+		
+		output.append(name);
+		
+		return output.toString();
+	}
+	
+	public boolean equals(Object other) {
+		if(!(other instanceof DatabaseTable)) {
+			return false;
+		}
+		DatabaseTable o = (DatabaseTable) other;
+		return o.catalog == this.catalog && o.schema == this.schema && o.name == this.name;
+	}
+	
+	
+	public int hashCode() {
+		int hash = catalog.hashCode() * 7;
+		hash += schema.hashCode() * 5;
+		hash += name.hashCode() * 3;
+		return hash;
+		
+	}
+	
+	public boolean presentInDatabase(Connection connection) throws SQLException {
+		ResultSet results = connection.getMetaData().getTables(catalog, schema, name, new String[]{"TABLE"});
+		boolean foundOne = results.next();
+		results.close();
+		return foundOne;
+	}
+	
+	public boolean hasPrimaryKey(Connection connection) throws SQLException {
+		return getPrimaryKeyColumns(connection).length != 0;
+	}
+	
+	public ForeignKey[] getRelations(Connection connection) throws SQLException {
+		ResultSet related = connection.getMetaData().getExportedKeys(catalog, schema, name);
+		Map<ForeignKeyNameWithTable, Set<ColumnPair>> correspondences = new HashMap<ForeignKeyNameWithTable, Set<ColumnPair>>();
+		while(related.next()) {
+			String foreignKeyName = related.getString(12);
+			DatabaseTable relatedTable = new DatabaseTable(related.getString(5), related.getString(6), related.getString(7));
+			ForeignKeyNameWithTable key = new ForeignKeyNameWithTable(foreignKeyName, relatedTable);
+			ColumnPair pair = new ColumnPair(related.getString(4), related.getString(8));
+			if(!correspondences.containsKey(key)) {
+				correspondences.put(key, new HashSet<ColumnPair>());
+			}
+			correspondences.get(key).add(pair);
+		}
+		
+		related.close();
+		
+		return makeForeignKeys(correspondences);
+	}
+
+	private ForeignKey[] makeForeignKeys(
+			Map<ForeignKeyNameWithTable, Set<ColumnPair>> correspondences) {
+		ForeignKey[] foreignKeys = new ForeignKey[correspondences.size()];
+		int index = 0;
+		for(Map.Entry<ForeignKeyNameWithTable, Set<ColumnPair>> entry : correspondences.entrySet()) {
+			foreignKeys[index] = new ForeignKey(this, entry.getKey().table, entry.getValue());
+			index++;
+		}
+		return foreignKeys;
+	}
+
+	public String[] getPrimaryKeyColumns(Connection connection) throws SQLException {
+		ResultSet columns = connection.getMetaData().getPrimaryKeys(catalog, schema, name);
+		List<String> columnNames = new ArrayList<String>();
+		while(columns.next()) {
+			columnNames.add(columns.getString(4));
+		}
+		return columnNames.toArray(new String[]{});
+	}
+
+	public void deleteRowsByColumns(List<Map<String, Object>> otherEntities, Connection connection) throws SQLException {
+		if(otherEntities.size() == 0) {
+			return;
+		}
+		List<String> columns = new ArrayList<String>(otherEntities.get(0).keySet());
+		String deleteStatement = constructDeleteStatement(columns, otherEntities);
+		connection.createStatement().executeUpdate(deleteStatement);
+	}
+
+	private String constructDeleteStatement(List<String> columns,
+			List<Map<String, Object>> otherEntities) {
+		return "DELETE FROM " + this.toString() + " WHERE " + DatabaseUtilities.getInExpression(columns, otherEntities);
+	}
+
+	public void duplicateTable(Connection originalConnection,
+			Connection newConnection) throws SQLException {
+		this.duplicateTableStructure(originalConnection, newConnection);
+		//TODO: finish
+		
+	}
+
+	public void duplicateTableStructure(Connection originalConnection,
+			Connection newConnection) throws SQLException {		
+		Column[] columns = getColumns(originalConnection);
+		String createStatement = createCreateStatement(columns);
+		newConnection.createStatement().executeUpdate(createStatement);
+	}
+
+	private String createCreateStatement(Column[] columns) {
+		List<String> definitions = new ArrayList<String>();
+		for(int ii = 0; ii < columns.length; ii++) {
+			definitions.add(columns[ii].getDefinition());
+		}
+		return "CREATE TABLE " + this.toString() + DatabaseUtilities.implodeAndWrap(definitions);
+	}
+
+	private Column[] getColumns(Connection connection) throws SQLException {
+		ResultSet results = connection.getMetaData().getColumns(this.catalog, this.schema, this.name, null);
+		List<Column> columns = new ArrayList<Column>();
+		while(results.next()) {
+			columns.add(new Column(results.getString(4), results.getInt(5), results.getInt(7)));
+		}
+		return columns.toArray(new Column[]{});
+	}
+
+	public void transferPrimaryKey(Connection originalConnection,
+			Connection newConnection) {
+		// TODO Auto-generated method stub
+		
+	}
+
+	public void pointForeignKeys(Connection originalConnection,
+			Connection newConnection) {
+		// TODO Auto-generated method stub
+		
+	}
+}
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKey.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKey.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKey.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,82 @@
+package org.cishell.utilities.database;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.cishell.utilities.DatabaseUtilities;
+import org.cishell.utilities.StringUtilities;
+
+public final class ForeignKey {
+
+	final public DatabaseTable localTable;
+	final public DatabaseTable otherTable;
+	final public Set<ColumnPair> pairs;
+
+	public ForeignKey(DatabaseTable localTable, DatabaseTable otherTable, Set<ColumnPair> pairs) {
+		this.localTable = localTable;
+		this.otherTable = otherTable;
+		this.pairs = Collections.unmodifiableSet(pairs);
+	}
+
+	public void repoint(List<Map<String, Object>> from,
+			Map<String, Object> to, Connection connection) throws SQLException {
+		
+		String updateQuery = constructUpdateQuery(from, to);
+		//TODO: remove
+		System.err.println("Issuing update: " + updateQuery);
+		connection.createStatement().executeUpdate(updateQuery);
+		
+	}
+
+	private String constructUpdateQuery(List<Map<String, Object>> from,
+			Map<String, Object> to) {
+		return "UPDATE " + otherTable.toString() + " SET "+ formatUpdates(to) + " WHERE "
+				+ DatabaseUtilities.getInExpression(getForeignColumnNames(), translateToForeignNames(from));
+	}
+
+	
+
+	private List<Map<String, Object>> translateToForeignNames(
+			List<Map<String, Object>> from) {
+		List<Map<String, Object>> output = new ArrayList<Map<String, Object>>();
+		for(Map<String, Object> fromValues : from) {
+			Map<String, Object> toValues = new HashMap<String, Object>();
+			for(ColumnPair pair : pairs) {
+				toValues.put(pair.foreign, fromValues.get(pair.local));
+			}
+			output.add(toValues);
+		}
+		
+		
+		return output;
+	}
+
+	private List<String> getForeignColumnNames() {
+		List<String> foreignColumns = new ArrayList<String>();
+		for(ColumnPair pair : pairs) {
+			foreignColumns.add(pair.foreign);
+		}
+		return foreignColumns;
+	}
+
+	
+
+	private String formatUpdates(Map<String, Object> to) {
+		List<String> updateStatements = new ArrayList<String>();
+		for(ColumnPair pair : pairs) {
+			String foreignColumn = pair.foreign;
+			Object newValue = to.get(pair.local);
+			updateStatements.add(foreignColumn + " = " + DatabaseUtilities.formatValue(newValue));
+		}
+		return StringUtilities.implodeList(updateStatements, ", ");
+	}
+	
+	
+
+}
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKeyNameWithTable.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKeyNameWithTable.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/ForeignKeyNameWithTable.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,23 @@
+package org.cishell.utilities.database;
+
+public final class ForeignKeyNameWithTable {
+	public final String name;
+	public final DatabaseTable table;
+	
+	public ForeignKeyNameWithTable(String name, DatabaseTable table) {
+		this.name = name;
+		this.table = table;
+	}
+	
+	public boolean equals(Object other) {
+		if(!(other instanceof ForeignKeyNameWithTable)) {
+			return false;
+		}
+		ForeignKeyNameWithTable o = (ForeignKeyNameWithTable) other;
+		return o.name.equals(this.name) && o.table.equals(this.table);
+	}
+	
+	public int hashCode() {
+		return name.hashCode() * 31 + table.hashCode();
+	}
+}
Added: trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/InvalidRepresentationException.java
===================================================================
--- trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/InvalidRepresentationException.java	                        (rev 0)
+++ trunk/core/org.cishell.utilities/src/org/cishell/utilities/database/InvalidRepresentationException.java	2010-01-21 20:31:28 UTC (rev 1020)
@@ -0,0 +1,14 @@
+package org.cishell.utilities.database;
+
+public class InvalidRepresentationException extends Exception {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	public InvalidRepresentationException(String message) {
+		super(message);
+	}
+
+}
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
 |