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

📄 database.java

📁 非常棒的java数据库
💻 JAVA
📖 第 1 页 / 共 4 页
字号:
/*
 * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
 * (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package org.h2.engine;

import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.StringTokenizer;

import org.h2.api.DatabaseEventListener;
import org.h2.command.dml.SetTypes;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.index.Cursor;
import org.h2.index.Index;
import org.h2.index.IndexType;
import org.h2.log.LogSystem;
import org.h2.log.UndoLogRecord;
import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.message.TraceSystem;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.schema.Schema;
import org.h2.schema.SchemaObject;
import org.h2.schema.Sequence;
import org.h2.store.DataHandler;
import org.h2.store.DataPage;
import org.h2.store.DiskFile;
import org.h2.store.FileLock;
import org.h2.store.FileStore;
import org.h2.store.RecordReader;
import org.h2.store.Storage;
import org.h2.store.WriterThread;
import org.h2.store.fs.FileSystem;
import org.h2.table.Column;
import org.h2.table.IndexColumn;
import org.h2.table.MetaTable;
import org.h2.table.Table;
import org.h2.table.TableData;
import org.h2.table.TableView;
import org.h2.tools.DeleteDbFiles;
import org.h2.util.BitField;
import org.h2.util.ByteUtils;
import org.h2.util.CacheLRU;
import org.h2.util.ClassUtils;
import org.h2.util.FileUtils;
import org.h2.util.IOUtils;
import org.h2.util.IntHashMap;
import org.h2.util.ObjectArray;
import org.h2.util.SmallLRUCache;
import org.h2.util.StringUtils;
import org.h2.value.CompareMode;
import org.h2.value.Value;
import org.h2.value.ValueInt;
import org.h2.value.ValueLob;

/**
 * There is one database object per open database.
 *
 * The format of the meta data table is:
 *  id int, headPos int (for indexes), objectType int, sql varchar
 *
 * @since 2004-04-15 22:49
 */
public class Database implements DataHandler {

    private final boolean persistent;
    private final String databaseName;
    private final String databaseShortName;
    private final String databaseURL;
    private final String cipher;
    private final byte[] filePasswordHash;

    private final HashMap roles = new HashMap();
    private final HashMap users = new HashMap();
    private final HashMap settings = new HashMap();
    private final HashMap schemas = new HashMap();
    private final HashMap rights = new HashMap();
    private final HashMap functionAliases = new HashMap();
    private final HashMap userDataTypes = new HashMap();
    private final HashMap aggregates = new HashMap();
    private final HashMap comments = new HashMap();
    private final Set sessions = Collections.synchronizedSet(new HashSet());
    private Session exclusiveSession;
    private final BitField objectIds = new BitField();
    private final Object lobSyncObject = new Object();

    private boolean textStorage;
    private Schema mainSchema;
    private Schema infoSchema;
    private int nextSessionId;
    private User systemUser;
    private Session systemSession;
    private TableData meta;
    private Index metaIdIndex;
    private FileLock lock;
    private LogSystem log;
    private WriterThread writer;
    private IntHashMap storageMap = new IntHashMap();
    private boolean starting;
    private DiskFile fileData, fileIndex;
    private TraceSystem traceSystem;
    private DataPage dummy;
    private int fileLockMethod;
    private Role publicRole;
    private long modificationDataId;
    private long modificationMetaId;
    private CompareMode compareMode;
    private String cluster = Constants.CLUSTERING_DISABLED;
    private boolean readOnly;
    private boolean noDiskSpace;
    private int writeDelay = Constants.DEFAULT_WRITE_DELAY;
    private DatabaseEventListener eventListener;
    private FileStore emergencyReserve;
    private int maxMemoryRows = Constants.DEFAULT_MAX_MEMORY_ROWS;
    private int maxMemoryUndo = SysProperties.DEFAULT_MAX_MEMORY_UNDO;
    private int lockMode = SysProperties.DEFAULT_LOCK_MODE;
    private boolean logIndexChanges;
    private int logLevel = 1;
    private int cacheSize;
    private int maxLengthInplaceLob = Constants.DEFAULT_MAX_LENGTH_INPLACE_LOB;
    private long biggestFileSize;
    private int allowLiterals = Constants.DEFAULT_ALLOW_LITERALS;

    private static int initialPowerOffCount;
    private int powerOffCount = initialPowerOffCount;
    private int closeDelay;
    private DatabaseCloser delayedCloser;
    private boolean recovery;
    private volatile boolean closing;
    private boolean ignoreCase;
    private boolean deleteFilesOnDisconnect;
    private String lobCompressionAlgorithm;
    private boolean optimizeReuseResults = true;
    private String cacheType;
    private boolean indexSummaryValid = true;
    private String accessModeLog, accessModeData;
    private boolean referentialIntegrity = true;
    private boolean multiVersion;
    private DatabaseCloser closeOnExit;
    private Mode mode = Mode.getInstance(Mode.REGULAR);
    // TODO change in version 1.1
    private boolean multiThreaded;
    private int maxOperationMemory = SysProperties.DEFAULT_MAX_OPERATION_MEMORY;
    private boolean lobFilesInDirectories = SysProperties.LOB_FILES_IN_DIRECTORIES;
    private SmallLRUCache lobFileListCache = new SmallLRUCache(128);

    public Database(String name, ConnectionInfo ci, String cipher) throws SQLException {
        this.compareMode = new CompareMode(null, null, 0);
        this.persistent = ci.isPersistent();
        this.filePasswordHash = ci.getFilePasswordHash();
        this.databaseName = name;
        this.databaseShortName = parseDatabaseShortName();
        this.cipher = cipher;
        String lockMethodName = ci.removeProperty("FILE_LOCK", null);
        this.accessModeLog = ci.removeProperty("ACCESS_MODE_LOG", "rw").toLowerCase();
        this.accessModeData = ci.removeProperty("ACCESS_MODE_DATA", "rw").toLowerCase();
        if ("r".equals(accessModeData)) {
            readOnly = true;
            accessModeLog = "r";
        }
        this.fileLockMethod = FileLock.getFileLockMethod(lockMethodName);
        this.textStorage = ci.getTextStorage();
        this.databaseURL = ci.getURL();
        this.eventListener = ci.removeDatabaseEventListenerObject();
        if (eventListener == null) {
            String listener = ci.removeProperty("DATABASE_EVENT_LISTENER", null);
            if (listener != null) {
                if (listener.startsWith("'")) {
                    listener = listener.substring(1);
                }
                if (listener.endsWith("'")) {
                    listener = listener.substring(0, listener.length() - 1);
                }
                setEventListener(listener);
            }
        }
        String log = ci.getProperty(SetTypes.LOG, null);
        if (log != null) {
            this.logIndexChanges = "2".equals(log);
        }
        String ignoreSummary = ci.getProperty("RECOVER", null);
        if (ignoreSummary != null) {
            this.recovery = true;
        }
        this.multiVersion = ci.removeProperty("MVCC", false);
        boolean closeAtVmShutdown = ci.removeProperty("DB_CLOSE_ON_EXIT", true);
        int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE);
        int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT,
                TraceSystem.DEFAULT_TRACE_LEVEL_SYSTEM_OUT);
        this.cacheType = StringUtils.toUpperEnglish(ci.removeProperty("CACHE_TYPE", CacheLRU.TYPE_NAME));
        try {
            open(traceLevelFile, traceLevelSystemOut);
            if (closeAtVmShutdown) {
                closeOnExit = new DatabaseCloser(this, 0, true);
                try {
                    Runtime.getRuntime().addShutdownHook(closeOnExit);
                } catch (IllegalStateException e) {
                    // shutdown in progress - just don't register the handler
                    // (maybe an application wants to write something into a
                    // database at shutdown time)
                } catch (SecurityException  e) {
                    // applets may not do that - ignore
                }
            }
        } catch (Throwable e) {
            if (traceSystem != null) {
                traceSystem.getTrace(Trace.DATABASE).error("opening " + databaseName, e);
                traceSystem.close();
            }
            closeOpenFilesAndUnlock();
            throw Message.convert(e);
        }
    }

    public static void setInitialPowerOffCount(int count) {
        initialPowerOffCount = count;
    }

    public void setPowerOffCount(int count) {
        if (powerOffCount == -1) {
            return;
        }
        powerOffCount = count;
    }

    public boolean getTextStorage() {
        return textStorage;
    }

    public static boolean isTextStorage(String fileName, boolean defaultValue) throws SQLException {
        byte[] magicText = Constants.MAGIC_FILE_HEADER_TEXT.getBytes();
        byte[] magicBinary = Constants.MAGIC_FILE_HEADER.getBytes();
        try {
            InputStream fin = FileUtils.openFileInputStream(fileName);
            byte[] magic = IOUtils.readBytesAndClose(fin, magicBinary.length);
            if (ByteUtils.compareNotNull(magic, magicText) == 0) {
                return true;
            } else if (ByteUtils.compareNotNull(magic, magicBinary) == 0) {
                return false;
            } else if (magic.length < magicText.length) {
                // file size is 0 or too small
                return defaultValue;
            }
            throw Message.getSQLException(ErrorCode.FILE_VERSION_ERROR_1, fileName);
        } catch (IOException e) {
            throw Message.convertIOException(e, fileName);
        }
    }

    public static byte[] getMagic(boolean textStorage) {
        if (textStorage) {
            return Constants.MAGIC_FILE_HEADER_TEXT.getBytes();
        } else {
            return Constants.MAGIC_FILE_HEADER.getBytes();
        }
    }

    public byte[] getMagic() {
        return getMagic(textStorage);
    }

    public boolean areEqual(Value a, Value b) throws SQLException {
        // TODO optimization possible
        // boolean is = a.compareEqual(b);
        // boolean is2 = a.compareTo(b, compareMode) == 0;
        // if(is != is2) {
        // is = a.compareEqual(b);
        // System.out.println("hey!");
        // }
        // return a.compareEqual(b);
        return a.compareTo(b, compareMode) == 0;
    }

    public int compare(Value a, Value b) throws SQLException {
        return a.compareTo(b, compareMode);
    }

    public int compareTypeSave(Value a, Value b) throws SQLException {
        return a.compareTypeSave(b, compareMode);
    }

    public long getModificationDataId() {
        return modificationDataId;
    }

    public long getNextModificationDataId() {
        return ++modificationDataId;
    }

    public long getModificationMetaId() {
        return modificationMetaId;
    }

    public long getNextModificationMetaId() {
        // if the meta data has been modified, the data is modified as well
        // (because MetaTable returns modificationDataId)
        modificationDataId++;
        return modificationMetaId++;
    }

    public int getPowerOffCount() {
        return powerOffCount;
    }

    public void checkPowerOff() throws SQLException {
        if (powerOffCount == 0) {
            return;
        }
        if (powerOffCount > 1) {
            powerOffCount--;
            return;
        }
        if (powerOffCount != -1) {
            try {
                powerOffCount = -1;
                if (log != null) {
                    try {
                        stopWriter();
                        log.close();
                    } catch (SQLException e) {
                        // ignore
                    }
                    log = null;
                }
                if (fileData != null) {
                    try {
                        fileData.close();
                    } catch (SQLException e) {
                        // ignore
                    }
                    fileData = null;
                }
                if (fileIndex != null) {
                    try {
                        fileIndex.close();
                    } catch (SQLException e) {
                        // ignore
                    }
                    fileIndex = null;
                }
                if (lock != null) {
                    lock.unlock();
                    lock = null;
                }
                if (emergencyReserve != null) {
                    emergencyReserve.closeAndDeleteSilently();
                    emergencyReserve = null;
                }
            } catch (Exception e) {
                TraceSystem.traceThrowable(e);
            }
        }
        Engine.getInstance().close(databaseName);
        throw Message.getSQLException(ErrorCode.SIMULATED_POWER_OFF);
    }

    public static boolean exists(String name) {
        return FileUtils.exists(name + Constants.SUFFIX_DATA_FILE);
    }

    public Trace getTrace(String module) {
        return traceSystem.getTrace(module);
    }

    public FileStore openFile(String name, String mode, boolean mustExist) throws SQLException {
        if (mustExist && !FileUtils.exists(name)) {
            throw Message.getSQLException(ErrorCode.FILE_NOT_FOUND_1, name);
        }
        FileStore store = FileStore.open(this, name, mode, getMagic(), cipher, filePasswordHash);
        try {
            store.init();
        } catch (SQLException e) {
            store.closeSilently();
            throw e;
        }
        return store;
    }

    public void checkFilePasswordHash(String c, byte[] hash) throws SQLException {
        if (!ByteUtils.compareSecure(hash, filePasswordHash) || !StringUtils.equals(c, cipher)) {
            try {
                Thread.sleep(Constants.DELAY_WRONG_PASSWORD);
            } catch (InterruptedException e) {
                // ignore
            }
            throw Message.getSQLException(ErrorCode.WRONG_USER_OR_PASSWORD);
        }
    }

    private void openFileData() throws SQLException {
        fileData = new DiskFile(this, databaseName + Constants.SUFFIX_DATA_FILE, accessModeData, true, true,
                SysProperties.CACHE_SIZE_DEFAULT);
    }

    private void openFileIndex() throws SQLException {
        fileIndex = new DiskFile(this, databaseName + Constants.SUFFIX_INDEX_FILE, accessModeData, false,
                logIndexChanges, SysProperties.CACHE_SIZE_INDEX_DEFAULT);
    }

    public DataPage getDataPage() {
        return dummy;
    }

    private String parseDatabaseShortName() {
        String n = databaseName;
        if (n.endsWith(":")) {
            n = null;
        }
        if (n != null) {
            StringTokenizer tokenizer = new StringTokenizer(n, "/\\:,;");
            while (tokenizer.hasMoreTokens()) {
                n = tokenizer.nextToken();
            }
        }
        if (n == null || n.length() == 0) {
            n = "UNNAMED";
        }
        return StringUtils.toUpperEnglish(n);
    }

    private synchronized void open(int traceLevelFile, int traceLevelSystemOut) throws SQLException {
        if (persistent) {
            String dataFileName = databaseName + Constants.SUFFIX_DATA_FILE;
            if (FileUtils.exists(dataFileName)) {
                // if it is already read-only because ACCESS_MODE_DATA=r
                readOnly = readOnly | FileUtils.isReadOnly(dataFileName);
                textStorage = isTextStorage(dataFileName, textStorage);
                lobFilesInDirectories |= FileUtils.exists(databaseName + Constants.SUFFIX_LOBS_DIRECTORY);
            }
        }

⌨️ 快捷键说明

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