/*- * 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 } }