⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 database.java

📁 這是一個油Java實作的資料庫系統 是個入門的好材料
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* =============================================================
 * SmallSQL : a free Java DBMS library for the Java(tm) platform
 * =============================================================
 *
 * (C) Copyright 2004-2007, by Volker Berlin.
 *
 * Project Info:  http://www.smallsql.de/
 *
 * 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.*;
import smallsql.database.language.Language;

/**
 * There are only one instance of this class per database. It will be share between all connections to this database and
 * all threads. That the access must be thread safe.
 * 
 * Here are save mainly table definitions and locks.
 */
final class Database{

    static private HashMap databases = new HashMap();

    final private TableViewMap tableViews = new TableViewMap();
    private String name;
	private File directory;
	private RandomAccessFile master;
	final private WeakHashMap connections = new WeakHashMap();


	/**
	 * Get a instance of the Database Class. If the Datbase with the given name is not open 
	 * then it will be open.
	 * @param name 	   the name of the database
	 * @param con 	   a referenz holder to this database, if all connection close that have a reference 
	 * 	               then the database can be unload.
	 * @param create   if the database not exist then create it
	 */
    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 SmallSQLException.create(Language.DB_NONEXISTENT, name);
            }
			directory = directory.getAbsoluteFile();
			File file = new File( directory, Utils.MASTER_FILENAME);
			if(!file.exists())
				throw SmallSQLException.create(Language.DB_NOT_DIRECTORY, name);
			master = Utils.openRaFile(file);
        }catch(Exception e){
        	throw SmallSQLException.createFromException(e);
        }
    }

    String getName(){
        return name;
    }
    
	
	

	/**
	 * Remove a connection from this database.
	 */
	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 {
						iterator.remove();
						database.close();
					} catch (Exception e) {
						throw SmallSQLException.createFromException(e);
					}
				}
			}
		}
	}
	

	/**
	 * Close all tables and views of this Database.
	 */
	private final void close() throws Exception{
		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);
    }

    
    /**
     * Return a TableView object. If the TableView object is not loaded then it load it.
     * @param con
     * @param tableName
     * @return ever a valid TableView object and never null.
     * @throws SQLException if the table or view does not exists
     */
    TableView getTableView(SSConnection con, String tableName) throws SQLException{
        synchronized(tableViews){
            TableView tableView = tableViews.get(tableName);
            if(tableView == null){
                // FIXME it should block only one table and not all tables, loading of the table should outside of the global synchronized
                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 );
            }
        }
    }
    
    
    void replaceTable( Table oldTable, Table newTable) throws Exception{
        synchronized(tableViews){
            tableViews.remove( oldTable.name );
            tableViews.remove( newTable.name );
            oldTable.close();
            newTable.close();
            File oldFile = oldTable.getFile(this);
            File newFile = newTable.getFile(this);
            File tmpFile = new File(Utils.createTableViewFileName( this, "#" + System.currentTimeMillis() + this.hashCode() ));
            if( !oldFile.renameTo(tmpFile) ){
                throw SmallSQLException.create(Language.TABLE_CANT_RENAME, oldTable.name);
            }
            if( !newFile.renameTo(oldFile) ){
                tmpFile.renameTo(oldFile); //restore the old table
                throw SmallSQLException.create(Language.TABLE_CANT_RENAME, oldTable.name);
            }
            tmpFile.delete();
        }
    }
    

	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 SmallSQLException.create(Language.VIEWDROP_NOT_VIEW, viewName);
			
			View.drop( this, viewName );
		}
	}
    
    
    private void checkForeignKeys( SSConnection con, ForeignKeys foreignKeys ) throws SQLException{
        for(int i=0; i<foreignKeys.size(); i++){
            ForeignKey foreignKey = foreignKeys.get(i);
            TableView pkTable = getTableView(con, foreignKey.pkTable);
            if(!(pkTable instanceof Table)){
                throw SmallSQLException.create(Language.FK_NOT_TABLE, foreignKey.pkTable);
            }
        }
    }
    

    /**
     * @param con current Connections
     * @param name the name of the new Table
     * @param columns the column descriptions of the table
     * @param indexes the indexes of the new table
     * @param foreignKeys 
     * @throws Exception
     */
	void createTable(SSConnection con, String name, Columns columns, IndexDescriptions indexes, ForeignKeys foreignKeys) throws Exception{
        checkForeignKeys( con, foreignKeys );
        // createFile() can run only one Thread success (it is atomic)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -