001package com.randomnoun.common.db; 002 003/* (c) 2013 randomnoun. All Rights Reserved. This work is licensed under a 004 * BSD Simplified License. (http://www.randomnoun.com/bsd-simplified.html) 005 */ 006 007import java.util.HashMap; 008 009import javax.sql.DataSource; 010 011import org.springframework.jdbc.core.JdbcTemplate; 012 013import com.randomnoun.common.db.to.SchemaTO; 014import com.randomnoun.common.db.to.TableColumnTO; 015import com.randomnoun.common.db.to.TableTO; 016 017/** Container class for database metadata. 018 * 019 * <p>Rewrite of DatabaseTO to be marginally more structured 020 * 021 * <p>Contains methods for populating metadata from the data dictionaries of 022 * Oracle and MySQL, for the purposes of whatever it is that I'm doing at the time. 023 * 024 * 025 * NB: does not set default values for oracle 026 * 027 */ 028public abstract class DatabaseReader { 029 030 protected com.randomnoun.common.db.to.DatabaseTO db; 031 032 // only required for online DB metadata 033 public DataSource ds; 034 public JdbcTemplate jt; 035 036 /* these aren't used yet 037 public static class SourceTypeTO { 038 public SchemaTO schema; 039 public List packages; 040 public List packageBodies; 041 public List procedures; 042 public List functions; 043 public List triggers; 044 } 045 046 public static class UserTypeTO { 047 public SchemaTO schema; 048 public List arrayTypes; 049 public List objectTypes; 050 public List tableTypes; 051 public List xmlSchema; 052 } 053 054 public static class SecurityTO { 055 public SchemaTO schema; 056 public List users; 057 public List roles; 058 public List profiles; 059 } 060 061 public static class StorageTO { 062 public SchemaTO schema; 063 public Map<String, TableTO> tablespaces; 064 public List datafiles; 065 public List rollbackSegments; 066 public List redoLogGroups; 067 public List archiveLogs; 068 } 069 070 public static class DistributedTO { 071 public SchemaTO schema; 072 public List inDoubtTransactions; 073 public List databaseLinks; 074 public List streams; 075 public List advancedQueues; 076 public List advancedReplication; 077 } 078 */ 079 080 /** Database metadata container. Will load reference data on demand */ 081 // @TODO look up correct Reader instance and use that 082 public DatabaseReader(DataSource dataSource /*, DatabaseType dbType*/) { 083 this.ds = dataSource; 084 this.jt = new JdbcTemplate(dataSource); 085 this.db = new com.randomnoun.common.db.to.DatabaseTO(); 086 db.setDatabaseType(null); 087 db.setSchemaMap(new HashMap<String, SchemaTO>()); 088 } 089 090 091 // this only works for MYSQL. so that's odd. 092 public SchemaTO getSchema(String schemaName) { 093 094 // default schema name 095 if (schemaName==null) { 096 switch (db.getDatabaseType()) { 097 case ORACLE: 098 throw new UnsupportedOperationException("Not supported for this database type"); 099 100 case MYSQL: 101 schemaName = (String) jt.queryForObject("SELECT DATABASE();", java.lang.String.class); 102 break; 103 104 case SQLSERVER: 105 throw new UnsupportedOperationException("Not supported for this database type"); 106 107 default: 108 throw new IllegalStateException("Unknown database type " + db.getDatabaseType()); 109 } 110 } 111 112 SchemaTO schema = db.getSchemaMap().get(db.upper(schemaName)); 113 if (schema == null) { 114 schema = readSchema(db.upper(schemaName)); 115 db.getSchemaMap().put(db.upper(schemaName), schema); 116 } 117 return schema; 118 } 119 120 abstract public SchemaTO readSchema(String schemaName); // SchemaTO schema 121 122 123 // @TODO pass in current schema/table for context resolution 124 public TableColumnTO getColumn(com.randomnoun.common.db.to.DatabaseTO db, String identifier) { 125 String schemaName = null; 126 String tableName = null; 127 String columnName = null; 128 String[] bits = identifier.split("\\."); 129 if (bits.length > 3) { throw new IllegalArgumentException("Too many components in column identifier '" + identifier + "'"); } 130 if (bits.length < 1) { throw new IllegalArgumentException("Too few components in column identifier '" + identifier + "'"); } 131 if (bits.length > 2) { schemaName = bits[bits.length - 3]; } 132 if (bits.length > 1) { tableName = bits[bits.length - 2]; } 133 columnName = bits[bits.length - 1]; 134 SchemaTO schema = db.getSchemaMap().get(schemaName); 135 TableTO table = schema.getTable(tableName); 136 return table.getTableColumn(columnName); 137 } 138 139}