/**
 * SqlJetDataBase.java
 * Copyright (C) 2009-2013 TMate Software Ltd
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program 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 General Public License for more details.
 *
 * For information on how to redistribute this software under
 * the terms of a license other than GNU General Public License
 * contact TMate Software at support@sqljet.com
 */
package org.tmatesoft.sqljet.core.table;

import java.io.File;
import java.io.IOException;

import org.tmatesoft.sqljet.core.SqlJetErrorCode;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.SqlJetTransactionMode;
import org.tmatesoft.sqljet.core.internal.ISqlJetFileSystem;
import org.tmatesoft.sqljet.core.internal.ISqlJetPager;
import org.tmatesoft.sqljet.core.internal.table.SqlJetPragmasHandler;
import org.tmatesoft.sqljet.core.internal.table.SqlJetTable;
import org.tmatesoft.sqljet.core.schema.ISqlJetIndexDef;
import org.tmatesoft.sqljet.core.schema.ISqlJetSchema;
import org.tmatesoft.sqljet.core.schema.ISqlJetTableDef;
import org.tmatesoft.sqljet.core.schema.ISqlJetTriggerDef;
import org.tmatesoft.sqljet.core.schema.ISqlJetViewDef;
import org.tmatesoft.sqljet.core.schema.ISqlJetVirtualTableDef;
import org.tmatesoft.sqljet.core.table.engine.ISqlJetEngineSynchronized;
import org.tmatesoft.sqljet.core.table.engine.ISqlJetEngineTransaction;
import org.tmatesoft.sqljet.core.table.engine.SqlJetEngine;

/**
 * 

* Connection to database. This class currently is main entry point in SQLJet * API. *

* *

* It allows to perform next tasks: * *

* *

* * @author TMate Software Ltd. * @author Sergey Scherbina (sergey.scherbina@gmail.com) * @author Dmitry Stadnik (dtrace@seznam.cz) */ public class SqlJetDb extends SqlJetEngine { /** * File name for in memory database. */ public static final File IN_MEMORY = new File(ISqlJetPager.MEMORY_DB); private SqlJetDb temporaryDb; /** *

* Creates connection to database but not open it. Doesn't open database * file until not called method {@link #open()}. *

* *

* File could be null or have special value {@link #IN_MEMORY}. If file is * null then will be created temporary file which will be deleted at close. * If file is {@link #IN_MEMORY} then file doesn't created and instead * database will placed in memory. If regular file is specified but doesn't * exist then it will be tried to created. *

* * @param file * path to data base. Could be null or {@link #IN_MEMORY}. * @param writable * if true then will allow data modification. */ public SqlJetDb(final File file, final boolean writable) { super(file, writable); } public SqlJetDb(final File file, final boolean writable, final ISqlJetFileSystem fs) { super(file, writable, fs); } public SqlJetDb(final File file, final boolean writable, final String fsName) throws SqlJetException { super(file, writable, fsName); } /** *

* Opens connection to data base. It does not create any locking on * database. First lock will be created when be called any method which * requires real access to options or schema. *

* *

* File could be null or have special value {@link #IN_MEMORY}. If file is * null then will be created temporary file which will be deleted at close. * If file is {@link #IN_MEMORY} then file doesn't created and instead * database will placed in memory. If regular file is specified but doesn't * exist then it will be tried to created. *

* * @param file * path to data base. Could be null or {@link #IN_MEMORY}. * @param write * open for writing if true. * @throws SqlJetException * if any trouble with access to file or database format. */ public static SqlJetDb open(File file, boolean write) throws SqlJetException { final SqlJetDb db = new SqlJetDb(file, write); db.open(); return db; } /** * @param file * @param write * @param fs * @return SqlJetDb object for opened database * @throws SqlJetException */ public static SqlJetDb open(File file, boolean write, final ISqlJetFileSystem fs) throws SqlJetException { final SqlJetDb db = new SqlJetDb(file, write, fs); db.open(); return db; } /** * @param file * @param write * @param fsName * @return SqlJetDb object for opened database * @throws SqlJetException */ public static SqlJetDb open(File file, boolean write, final String fsName) throws SqlJetException { final SqlJetDb db = new SqlJetDb(file, write, fsName); db.open(); return db; } /** * Do some actions with locking database's internal threads synchronization * mutex. It is related only with synchronization of access to one * connection from multiple threads. It is not related with transactions and * locks of database file. For concurrent access to database from threads or * processes use transactions. * * @param op operation to run * @return result of the {@link ISqlJetRunnableWithLock#runWithLock(SqlJetDb)} call. * * @throws SqlJetException in case operation fails to run. */ public Object runWithLock(final ISqlJetRunnableWithLock op) throws SqlJetException { return runSynchronized(new ISqlJetEngineSynchronized() { public Object runSynchronized(SqlJetEngine db) throws SqlJetException { return op.runWithLock(SqlJetDb.this); } }); } /** * Get database schema. * * @return database schema. */ public ISqlJetSchema getSchema() throws SqlJetException { return getSchemaInternal(); } /** * Open table. * * @param tableName name of the table to open. * @return opened table */ public ISqlJetTable getTable(final String tableName) throws SqlJetException { checkOpen(); refreshSchema(); return (SqlJetTable) runWithLock(new ISqlJetRunnableWithLock() { public Object runWithLock(SqlJetDb db) throws SqlJetException { return new SqlJetTable(db, btree, tableName, writable); } }); } /** * Run modifications in write transaction. * * @param op transaction to run. * @return result of the {@link ISqlJetTransaction#run(SqlJetDb)} call. */ public Object runWriteTransaction(ISqlJetTransaction op) throws SqlJetException { checkOpen(); if (writable) { return runTransaction(op, SqlJetTransactionMode.WRITE); } else { throw new SqlJetException(SqlJetErrorCode.MISUSE, "Can't start write transaction on read-only database"); } } /** * Run read-only transaction. * * @param op transaction to run. * @return result of the {@link ISqlJetTransaction#run(SqlJetDb)} call. */ public Object runReadTransaction(ISqlJetTransaction op) throws SqlJetException { checkOpen(); return runTransaction(op, SqlJetTransactionMode.READ_ONLY); } /** * Run transaction. * * @param op * transaction's body (closure). * @param mode * transaction's mode. * @return result of the {@link ISqlJetTransaction#run(SqlJetDb)} call. */ public Object runTransaction(final ISqlJetTransaction op, final SqlJetTransactionMode mode) throws SqlJetException { return runEngineTransaction(new ISqlJetEngineTransaction() { public Object run(SqlJetEngine engine) throws SqlJetException { return op.run(SqlJetDb.this); } }, mode); } /** * Executes pragma statement. If statement queries pragma value then pragma * value will be returned. */ public Object pragma(final String sql) throws SqlJetException { checkOpen(); refreshSchema(); return runWithLock(new ISqlJetRunnableWithLock() { public Object runWithLock(SqlJetDb db) throws SqlJetException { return new SqlJetPragmasHandler(getOptions()).pragma(sql); } }); } /** * Create table from SQL clause. * * @param sql * CREATE TABLE ... sentence. * @return definition of create table. */ public ISqlJetTableDef createTable(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetTableDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().createTable(sql); } }); } /** * Create index from SQL clause. * * @param sql * CREATE INDEX ... sentence. * @return definition of created index. */ public ISqlJetIndexDef createIndex(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetIndexDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().createIndex(sql); } }); } /** * Drop table. * * @param tableName name of table to drop. */ public void dropTable(final String tableName) throws SqlJetException { checkOpen(); runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { getSchemaInternal().dropTable(tableName); return null; } }); } /** * Drop index. * * @param indexName name of the index to drop. */ public void dropIndex(final String indexName) throws SqlJetException { checkOpen(); runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { getSchemaInternal().dropIndex(indexName); return null; } }); } /** * Drop view. * * @param viewName name of the view to drop. */ public void dropView(final String viewName) throws SqlJetException { checkOpen(); runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { getSchemaInternal().dropView(viewName); return null; } }); } /** * Drop trigger. * * @param triggerName name of the trigger to drop. */ public void dropTrigger(final String triggerName) throws SqlJetException { checkOpen(); runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { getSchemaInternal().dropTrigger(triggerName); return null; } }); } /** * Alters table. * * @param sql * ALTER TABLE ... sentence. * @return altered table schema definition. */ public ISqlJetTableDef alterTable(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetTableDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().alterTable(sql); } }); } /** * Creates virtual table from SQL clause. * * @param sql * CREATE VIRTUAL TABLE ... sentence. * @return definition of create virtual table. */ public ISqlJetVirtualTableDef createVirtualTable(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetVirtualTableDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().createVirtualTable(sql, 0); } }); } /** * Creates view from SQL clause. * * @param sql * CREATE VIEW X AS SELECT ... sentence. * @return definition of the view being created. */ public ISqlJetViewDef createView(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetViewDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().createView(sql); } }); } /** * Creates trigger from SQL clause. * * @param sql * CREATE TRIGGER ... sentence. * @return definition of the trigger being created. */ public ISqlJetTriggerDef createTrigger(final String sql) throws SqlJetException { checkOpen(); return (ISqlJetTriggerDef) runWriteTransaction(new ISqlJetTransaction() { public Object run(SqlJetDb db) throws SqlJetException { return getSchemaInternal().createTrigger(sql); } }); } /** * @see #getTemporaryDatabase(boolean) * * @return SqlJetDb object for temporary database * @throws SqlJetException */ public SqlJetDb getTemporaryDatabase() throws SqlJetException { return getTemporaryDatabase(false); } /** * Opens temporary on-disk database which life span is less or equal to that * of this object. Temporary database is closed and deleted as soon as * this database connection is closed. * * Temporary file is used to store temporary database. * * Subsequent calls to this method will return the same temporary database * In case previously create temporary database is closed by the user, * then another one is created by this method. * * @param inMemory when true open temporary database in memory. * * @return temporary database being created or existing temporary database. * @throws SqlJetException */ public SqlJetDb getTemporaryDatabase(final boolean inMemory) throws SqlJetException { checkOpen(); return (SqlJetDb) runWithLock(new ISqlJetRunnableWithLock() { public Object runWithLock(SqlJetDb db) throws SqlJetException { if (temporaryDb == null || !temporaryDb.isOpen()) { closeTemporaryDatabase(); final File tmpDbFile = getTemporaryDatabaseFile(inMemory); if (tmpDbFile != null) { temporaryDb = SqlJetDb.open(tmpDbFile, true); } } return temporaryDb; } }); } @Override protected void closeResources() throws SqlJetException { closeTemporaryDatabase(); } private void closeTemporaryDatabase() throws SqlJetException { if (temporaryDb != null) { temporaryDb.close(); File tmpDbFile = temporaryDb.getFile(); if (tmpDbFile != null && !IN_MEMORY.equals(tmpDbFile)) { getFileSystem().delete(tmpDbFile, false); } } temporaryDb = null; } private File getTemporaryDatabaseFile(boolean inMemory) throws SqlJetException { if (inMemory) { return IN_MEMORY; } File tmpDbFile = null; try { tmpDbFile = getFileSystem().getTempFile(); } catch (IOException e) { throw new SqlJetException(SqlJetErrorCode.CANTOPEN, e); } if (tmpDbFile == null) { throw new SqlJetException(SqlJetErrorCode.CANTOPEN); } return tmpDbFile; } }

Ads help maintain this website.