*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ---------------
* Database.java
* ---------------
* Author: Volker Berlin
*
*/
package smallsql.database;
import java.util.*;
import java.io.*;
import java.sql.*;
final class Database {
static private HashMap databases = new HashMap();
final private HashMap tableViews = new HashMap();
private String name;
private File directory;
private RandomAccessFile master;
final private WeakHashMap connections = new WeakHashMap();
static Database getDatabase( String name, SSConnection con, boolean create ) throws SQLException{
if(name == null) return null;
if(name.startsWith("file:"))
name = name.substring(5);
if(File.separatorChar == '\\')
name = name.replace( '/', File.separatorChar);
else
name = name.replace( '\\', File.separatorChar);
synchronized(databases){
Database db = (Database)databases.get(name);
if(db == null){
if(create && !new File(name).isDirectory()){
CommandCreateDatabase command = new CommandCreateDatabase(con.log,name);
command.execute(con,null);
}
db = new Database(name);
databases.put( name, db);
}
db.connections.put(con, null);
return db;
}
}
private static Database getDatabase(SSConnection con, String name) throws SQLException{
return name == null ?
con.getDatabase(false) :
getDatabase( name, con, false );
}
private Database(String name ) throws SQLException{
try{
this.name = name;
directory = new File(name);
if(!directory.isDirectory()){
throw Utils.createSQLException("Database '" + name + "' does not exists.");
}
directory = directory.getAbsoluteFile();
File file = new File( directory, Utils.MASTER_FILENAME);
if(!file.exists())
throw Utils.createSQLException("Directory '" + name + "' is not a SmallSQL database.");
master = new RandomAccessFile( file, "rw");
}catch(Exception e){
throw Utils.createSQLException(e);
}
}
String getName(){
return name;
}
static final void closeConnection(SSConnection con) throws SQLException{
synchronized(databases){
Iterator iterator = databases.values().iterator();
while(iterator.hasNext()){
Database database = (Database)iterator.next();
WeakHashMap connections = database.connections;
connections.remove(con);
if(connections.size() == 0){
try {
database.close();
} catch (Exception e) {
throw Utils.createSQLException(e);
}
}
}
}
}
final void close() throws Exception{
databases.remove(this.name);
synchronized(tableViews){
Iterator iterator = tableViews.values().iterator();
while(iterator.hasNext()){
TableView tableView = (TableView)iterator.next();
tableView.close();
iterator.remove();
}
}
master.close();
}
static TableView getTableView(SSConnection con, String catalog, String tableName) throws SQLException{
return getDatabase( con, catalog).getTableView( con, tableName);
}
TableView getTableView(SSConnection con, String tableName) throws SQLException{
synchronized(tableViews){
TableView tableView = (TableView)tableViews.get(tableName);
if(tableView == null){
tableView = TableView.load(con, this, tableName);
tableViews.put( tableName, tableView);
}
return tableView;
}
}
static void dropTable(SSConnection con, String catalog, String tableName) throws Exception{
getDatabase( con, catalog).dropTable( con, tableName);
}
void dropTable(SSConnection con, String tableName) throws Exception{
synchronized(tableViews){
Table table = (Table)tableViews.get( tableName );
if(table != null){
tableViews.remove( tableName );
table.drop(con);
}else{
Table.drop( this, tableName );
}
}
}
static void dropView(SSConnection con, String catalog, String tableName) throws Exception{
getDatabase( con, catalog).dropView(tableName);
}
void dropView(String viewName) throws Exception{
synchronized(tableViews){
Object view = tableViews.remove( viewName );
if(view != null && !(view instanceof View))
throw Utils.createSQLException("Cannot use DROP VIEW with '" + viewName + "' because it does not is a view.");
View.drop( this, viewName );
}
}
void createTable(SSConnection con, String name, Columns columns, IndexDescriptions indexes) throws Exception{
Table table = new Table( this, con, name, columns, indexes);
synchronized(tableViews){
tableViews.put( name, table);
}
}
void createView(String name, String sql) throws Exception{
new View( this, name, sql);
}
static Object[][] getCatalogs(Database database){
List catalogs = new ArrayList();
File baseDir = (database != null) ?
database.directory.getParentFile() :
new File(".");
File dirs[] = baseDir.listFiles();
if(dirs != null)
for(int i=0; i<dirs.length; i++){
if(dirs[i].isDirectory()){
if(new File(dirs[i], Utils.MASTER_FILENAME).exists()){
Object[] catalog = new Object[1];
catalog[0] = dirs[i].getPath();
catalogs.add(catalog);
}
}
}
Object[][] result = new Object[catalogs.size()][];
catalogs.toArray(result);
return result;
}
Strings getTables(String tablePattern){
Strings list = new Strings();
File dirs[] = directory.listFiles();
if(dirs != null)
if(tablePattern == null) tablePattern = "%";
tablePattern += Utils.TABLE_VIEW_EXTENTION;
for(int i=0; i<dirs.length; i++){
String name = dirs[i].getName();
if(Utils.like(name, tablePattern)){
list.add(name.substring( 0, name.length()-Utils.TABLE_VIEW_EXTENTION.length() ));
}
}
return list;
}
Object[][] getColumns( SSConnection con, String tablePattern, String colPattern) throws Exception{
List rows = new ArrayList();
Strings tables = getTables(tablePattern);
for(int i=0; i<tables.size(); i++){
String tableName = tables.get(i);
try{
TableView tab = getTableView( con, tableName);
Columns cols = tab.columns;
for(int c=0; c<cols.size(); c++){
Column col = cols.get(c);
Object[] row = new Object[18];
row[0] = getName(); row[2] = tableName; row[3] = col.getName(); row[4] = Utils.getShort( SQLTokenizer.getSQLDataType( col.getDataType() )); row[5] = SQLTokenizer.getKeyWord( col.getDataType() ); row[6] = Utils.getInteger(col.getColumnSize()); row[8] = Utils.getInteger(col.getScale()); row[9] = Utils.getInteger(10); row[10]= Utils.getInteger(col.isNullable() ? DatabaseMetaData.columnNullable : DatabaseMetaData.columnNoNulls); row[12]= col.getDefaultDefinition(); row[15]= row[6]; row[16]= Utils.getInteger(i); row[17]= col.isNullable() ? "YES" : "NO"; rows.add(row);
}
}catch(Exception e){
}
}
Object[][] result = new Object[rows.size()][];
rows.toArray(result);
return result;
}
Object[][] getReferenceKeys(SSConnection con, String pkTable, String fkTable) throws SQLException{
List rows = new ArrayList();
Strings tables = (pkTable != null) ? getTables(pkTable) : getTables(fkTable);
for(int t=0; t<tables.size(); t++){
String tableName = tables.get(t);
TableView tab = getTableView( con, tableName);
if(!(tab instanceof Table)) continue;
ForeignKeys references = ((Table)tab).references;
for(int i=0; i<references.size(); i++){
ForeignKey foreignKey = references.get(i);
IndexDescription pk = foreignKey.pk;
IndexDescription fk = foreignKey.fk;
if((pkTable == null || pkTable.equals(foreignKey.pkTable)) &&
(fkTable == null || fkTable.equals(foreignKey.fkTable))){
Strings columnsPk = pk.getColumns();
Strings columnsFk = fk.getColumns();
for(int c=0; c<columnsPk.size(); c++){
Object[] row = new Object[14];
row[0] = getName(); row[2] = foreignKey.pkTable; row[3] = columnsPk.get(c); row[4] = getName(); row[6] = foreignKey.fkTable; row[7] = columnsFk.get(c); row[8] = Utils.getShort(c+1); row[9] = Utils.getShort(foreignKey.updateRule); row[10]= Utils.getShort(foreignKey.deleteRule); row[11]= fk.getName(); row[12]= pk.getName(); row[13]= Utils.getShort(DatabaseMetaData.importedKeyNotDeferrable); rows.add(row);
}
}
}
}
Object[][] result = new Object[rows.size()][];
rows.toArray(result);
return result;
}
Object[][] getBestRowIdentifier(SSConnection con, String table) throws SQLException{
List rows = new ArrayList();
Strings tables = getTables(table);
for(int t=0; t<tables.size(); t++){
String tableName = tables.get(t);
TableView tab = getTableView( con, tableName);
if(!(tab instanceof Table)) continue;
IndexDescriptions indexes = ((Table)tab).indexes;
for(int i=0; i<indexes.size(); i++){
IndexDescription index = indexes.get(i);
if(index.isUnique()){
Strings columns = index.getColumns();
for(int c=0; c<columns.size(); c++){
String columnName = columns.get(c);
Column column = tab.findColumn(columnName);
Object[] row = new Object[8];
row[0] = Utils.getShort(DatabaseMetaData.bestRowTransaction); row[1] = columnName; final int dataType = column.getDataType();
row[2] = Utils.getInteger(dataType); row[3] = SQLTokenizer.getKeyWord(dataType); row[4] = Utils.getInteger(column.getPrecision()); row[6] = Utils.getInteger(column.getScale()); row[7] = Utils.getShort(DatabaseMetaData.bestRowNotPseudo); rows.add(row);
}
}
}
}
Object[][] result = new Object[rows.size()][];
rows.toArray(result);
return result;
}
Object[][] getPrimaryKeys(SSConnection con, String table) throws SQLException{
List rows = new ArrayList();
Strings tables = getTables(table);
for(int t=0; t<tables.size(); t++){
String tableName = tables.get(t);
TableView tab = getTableView( con, tableName);
if(!(tab instanceof Table)) continue;
IndexDescriptions indexes = ((Table)tab).indexes;
for(int i=0; i<indexes.size(); i++){
IndexDescription index = indexes.get(i);
if(index.isPrimary()){
Strings columns = index.getColumns();
for(int c=0; c<columns.size(); c++){
Object[] row = new Object[6];
row[0] = getName(); row[2] = tableName; row[3] = columns.get(c); row[4] = Utils.getShort(c+1); row[5] = index.getName(); rows.add(row);
}
}
}
}
Object[][] result = new Object[rows.size()][];
rows.toArray(result);
return result;
}
Object[][] getIndexInfo( SSConnection con, String table, boolean unique) throws SQLException {
List rows = new ArrayList();
Strings tables = getTables(table);
Short type = Utils.getShort( DatabaseMetaData.tableIndexOther );
for(int t=0; t<tables.size(); t++){
String tableName = tables.get(t);
TableView tab = getTableView( con, tableName);
if(!(tab instanceof Table)) continue;
IndexDescriptions indexes = ((Table)tab).indexes;
for(int i=0; i<indexes.size(); i++){
IndexDescription index = indexes.get(i);
Strings columns = index.getColumns();
for(int c=0; c<columns.size(); c++){
Object[] row = new Object[13];
row[0] = getName(); row[2] = tableName; row[3] = Boolean.valueOf(!index.isUnique()); row[5] = index.getName(); row[6] = type; row[7] = Utils.getShort(c+1); row[8] = columns.get(c); rows.add(row);
}
}
}
Object[][] result = new Object[rows.size()][];
rows.toArray(result);
return result;
}
}