/*-
* See the file LICENSE for redistribution information.
*
* Copyright (c) 2009 Oracle. All rights reserved.
*
*/
using System;
using System.Collections.Generic;
using System.Text;
using BerkeleyDB.Internal;
namespace BerkeleyDB {
///
/// A class representing a secondary Berkeley DB database, a base class for
/// access method specific classes.
///
public class SecondaryDatabase : BaseDatabase {
private SecondaryKeyGenDelegate keyGenHandler;
internal BDB_AssociateDelegate doAssocRef;
private ForeignKeyNullifyDelegate nullifierHandler;
internal BDB_AssociateForeignDelegate doNullifyRef;
#region Constructors
///
/// Protected construtor
///
/// The environment in which to open the DB
/// Flags to pass to DB->create
protected SecondaryDatabase(DatabaseEnvironment env, uint flags)
: base(env, flags) { }
internal static SecondaryDatabase fromDB(DB dbp) {
try {
return (SecondaryDatabase)dbp.api_internal;
} catch { }
return null;
}
///
/// Protected method to configure the DB. Only valid before DB->open.
///
/// Configuration parameters.
protected void Config(SecondaryDatabaseConfig cfg) {
base.Config(cfg);
KeyGen = cfg.KeyGen;
Nullifier = cfg.ForeignKeyNullfier;
db.set_flags(cfg.flags);
}
///
/// Instantiate a new SecondaryDatabase object, open the database
/// represented by and associate the
/// database with the
/// primary index. The file specified by
/// must exist.
///
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database.
///
/// The database's configuration
/// A new, open database object
public static SecondaryDatabase Open(
string Filename, SecondaryDatabaseConfig cfg) {
return Open(Filename, null, cfg, null);
}
///
/// Instantiate a new SecondaryDatabase object, open the database
/// represented by and associate the
/// database with the
/// primary index. The file specified by
/// must exist.
///
///
///
/// If is null and
/// is non-null, the database can be
/// opened by other threads of control and will be replicated to client
/// sites in any replication group.
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database.
///
///
/// This parameter allows applications to have multiple databases in a
/// single file. Although no DatabaseName needs to be specified, it is
/// an error to attempt to open a second database in a file that was not
/// initially created using a database name.
///
/// The database's configuration
/// A new, open database object
public static SecondaryDatabase Open(string Filename,
string DatabaseName, SecondaryDatabaseConfig cfg) {
return Open(Filename, DatabaseName, cfg, null);
}
///
/// Instantiate a new SecondaryDatabase object, open the database
/// represented by and associate the
/// database with the
/// primary index. The file specified by
/// must exist.
///
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database.
///
/// The database's configuration
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// A new, open database object
public static SecondaryDatabase Open(string Filename,
SecondaryDatabaseConfig cfg, Transaction txn) {
return Open(Filename, null, cfg, txn);
}
///
/// Instantiate a new SecondaryDatabase object, open the database
/// represented by and associate the
/// database with the
/// primary index. The file specified by
/// must exist.
///
///
///
/// If is null and
/// is non-null, the database can be
/// opened by other threads of control and will be replicated to client
/// sites in any replication group.
///
///
/// If is set, the operation
/// will be implicitly transaction protected. Note that transactionally
/// protected operations on a datbase object requires the object itself
/// be transactionally protected during its open.
///
///
///
/// The name of an underlying file that will be used to back the
/// database.
///
///
/// This parameter allows applications to have multiple databases in a
/// single file. Although no DatabaseName needs to be specified, it is
/// an error to attempt to open a second database in a file that was not
/// initially created using a database name.
///
/// The database's configuration
///
/// If the operation is part of an application-specified transaction,
/// is a Transaction object returned from
/// ; if
/// the operation is part of a Berkeley DB Concurrent Data Store group,
/// is a handle returned from
/// ; otherwise null.
///
/// A new, open database object
public static SecondaryDatabase Open(string Filename,
string DatabaseName, SecondaryDatabaseConfig cfg, Transaction txn) {
if (cfg.DbType == DatabaseType.BTREE) {
return SecondaryBTreeDatabase.Open(Filename,
DatabaseName, (SecondaryBTreeDatabaseConfig)cfg, txn);
} else if (cfg.DbType == DatabaseType.HASH) {
return SecondaryHashDatabase.Open(Filename,
DatabaseName, (SecondaryHashDatabaseConfig)cfg, txn);
}
SecondaryDatabase ret = new SecondaryDatabase(cfg.Env, 0);
ret.Config(cfg);
ret.db.open(Transaction.getDB_TXN(txn), Filename,
DatabaseName, cfg.DbType.getDBTYPE(), cfg.openFlags, 0);
ret.doAssocRef = new BDB_AssociateDelegate(doAssociate);
cfg.Primary.db.associate(Transaction.getDB_TXN(null),
ret.db, ret.doAssocRef, cfg.assocFlags);
if (cfg.ForeignKeyDatabase != null) {
if (cfg.OnForeignKeyDelete == ForeignKeyDeleteAction.NULLIFY)
ret.doNullifyRef =
new BDB_AssociateForeignDelegate(doNullify);
else
ret.doNullifyRef = null;
cfg.ForeignKeyDatabase.db.associate_foreign(ret.db,
ret.doNullifyRef, cfg.foreignFlags);
}
return ret;
}
#endregion Constructors
#region Callbacks
///
/// Protected method to call the key generation function.
///
/// Secondary DB Handle
/// Primary Key
/// Primary Data
/// Scondary Key
/// 0 on success, !0 on failure
protected static int doAssociate(
IntPtr dbp, IntPtr keyp, IntPtr datap, IntPtr skeyp) {
DB db = new DB(dbp, false);
DBT key = new DBT(keyp, false);
DBT data = new DBT(datap, false);
DBT skey = new DBT(skeyp, false);
DatabaseEntry s =
((SecondaryDatabase)db.api_internal).KeyGen(
DatabaseEntry.fromDBT(key), DatabaseEntry.fromDBT(data));
if (s == null)
return DbConstants.DB_DONOTINDEX;
skey.data = s.Data;
return 0;
}
///
/// Protected method to nullify a foreign key
///
/// Secondary DB Handle
/// Primary Key
/// Primary Data
/// Foreign Key
/// Whether the foreign key has changed
/// 0 on success, !0 on failure
protected static int doNullify(IntPtr dbp,
IntPtr keyp, IntPtr datap, IntPtr fkeyp, ref int changed) {
DB db = new DB(dbp, false);
DBT key = new DBT(keyp, false);
DBT data = new DBT(datap, false);
DBT fkey = new DBT(fkeyp, false);
DatabaseEntry d = ((SecondaryDatabase)db.api_internal).Nullifier(
DatabaseEntry.fromDBT(key),
DatabaseEntry.fromDBT(data), DatabaseEntry.fromDBT(fkey));
if (d == null)
changed = 0;
else {
changed = 1;
data.data = d.Data;
}
return 0;
}
#endregion Callbacks
#region Properties
///
/// The delegate that creates the set of secondary keys corresponding to
/// a given primary key and data pair.
///
public SecondaryKeyGenDelegate KeyGen {
get { return keyGenHandler; }
private set {
keyGenHandler = value;
}
}
public ForeignKeyNullifyDelegate Nullifier {
get { return nullifierHandler; }
private set { nullifierHandler = value; }
}
#endregion Properties
#region Methods
///
/// Create a secondary database cursor.
///
/// A newly created cursor
public SecondaryCursor SecondaryCursor() {
return SecondaryCursor(new CursorConfig(), null);
}
///
/// Create a secondary database cursor with the given configuration.
///
///
/// The configuration properties for the cursor.
///
/// A newly created cursor
public SecondaryCursor SecondaryCursor(CursorConfig cfg) {
return SecondaryCursor(cfg, null);
}
///
/// Create a transactionally protected secondary database cursor.
///
///
/// The transaction context in which the cursor may be used.
///
/// A newly created cursor
public SecondaryCursor SecondaryCursor(Transaction txn) {
return SecondaryCursor(new CursorConfig(), txn);
}
///
/// Create a transactionally protected secondary database cursor with
/// the given configuration.
///
///
/// The configuration properties for the cursor.
///
///
/// The transaction context in which the cursor may be used.
///
/// A newly created cursor
public SecondaryCursor SecondaryCursor(
CursorConfig cfg, Transaction txn) {
return new SecondaryCursor(
db.cursor(Transaction.getDB_TXN(txn), cfg.flags));
}
#endregion Methods
}
}