1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2009, 2013 Oracle and/or its affiliates.  All rights reserved.
5  *
6  */
7 using System;
8 using System.Collections.Generic;
9 using System.IO;
10 using System.Text;
11 using BerkeleyDB.Internal;
12 
13 namespace BerkeleyDB {
14     /// <summary>
15     /// A class representing a Berkeley DB database, a base class for access
16     /// method specific classes.
17     /// </summary>
18     public class Database : BaseDatabase, IDisposable {
19         private static BDB_FileWriteDelegate writeToFileRef;
20 
21         #region Constructors
22         /// <summary>
23         /// Protected constructor
24         /// </summary>
25         /// <param name="env">
26         /// The environment in which to create this database
27         /// </param>
28         /// <param name="flags">Flags to pass to the DB->create() method</param>
Database(DatabaseEnvironment env, uint flags)29         protected Database(DatabaseEnvironment env, uint flags)
30             : base(env, flags) {
31         }
32         /// <summary>
33         /// Create a new database object with the same underlying DB handle as
34         /// <paramref name="clone"/>.  Used during Database.Open to get an
35         /// object of the correct DBTYPE.
36         /// </summary>
37         /// <param name="clone">Database to clone</param>
Database(BaseDatabase clone)38         protected Database(BaseDatabase clone) : base(clone) { }
fromDB(DB dbp)39         internal static Database fromDB(DB dbp) {
40             try {
41                 return (Database)dbp.api_internal;
42             } catch { }
43             return null;
44         }
45 
46         /// <summary>
47         /// Instantiate a new Database object and open the database represented
48         /// by <paramref name="Filename"/>. The file specified by
49         /// <paramref name="Filename"/> must exist.
50         /// </summary>
51         /// <remarks>
52         /// <para>
53         /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
54         /// will be implicitly transaction protected. Note that transactionally
55         /// protected operations on a datbase object requires the object itself
56         /// be transactionally protected during its open.
57         /// </para>
58         /// </remarks>
59         /// <param name="Filename">
60         /// The name of an underlying file that will be used to back the
61         /// database.
62         /// </param>
63         /// <param name="cfg">The database's configuration</param>
64         /// <returns>A new, open database object</returns>
Open(string Filename, DatabaseConfig cfg)65         public static Database Open(string Filename, DatabaseConfig cfg) {
66             return Open(Filename, null, cfg, null);
67         }
68         /// <summary>
69         /// Instantiate a new Database object and open the database represented
70         /// by <paramref name="Filename"/> and <paramref name="DatabaseName"/>.
71         /// The file specified by <paramref name="Filename"/> must exist.
72         /// </summary>
73         /// <remarks>
74         /// <para>
75         /// If <paramref name="Filename"/> is null and
76         /// <paramref name="DatabaseName"/> is non-null, the database can be
77         /// opened by other threads of control and will be replicated to client
78         /// sites in any replication group.
79         /// </para>
80         /// <para>
81         /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
82         /// will be implicitly transaction protected. Note that transactionally
83         /// protected operations on a datbase object requires the object itself
84         /// be transactionally protected during its open.
85         /// </para>
86         /// </remarks>
87         /// <param name="Filename">
88         /// The name of an underlying file that will be used to back the
89         /// database. In-memory databases never intended to be preserved on disk
90         /// may be created by setting this parameter to null.</param>
91         /// <param name="DatabaseName">
92         /// This parameter allows applications to have multiple databases in a
93         /// single file. Although no DatabaseName needs to be specified, it is
94         /// an error to attempt to open a second database in a file that was not
95         /// initially created using a database name.
96         /// </param>
97         /// <param name="cfg">The database's configuration</param>
98         /// <returns>A new, open database object</returns>
Open( string Filename, string DatabaseName, DatabaseConfig cfg)99         public static Database Open(
100             string Filename, string DatabaseName, DatabaseConfig cfg) {
101             return Open(Filename, DatabaseName, cfg, null);
102         }
103         /// <summary>
104         /// Instantiate a new Database object and open the database represented
105         /// by <paramref name="Filename"/>. The file specified by
106         /// <paramref name="Filename"/> must exist.
107         /// </summary>
108         /// <remarks>
109         /// <para>
110         /// If <paramref name="Filename"/> is null, the database is strictly
111         /// temporary and cannot be opened by any other thread of control, thus
112         /// the database can only be accessed by sharing the single database
113         /// object that created it, in circumstances where doing so is safe.
114         /// </para>
115         /// <para>
116         /// If <paramref name="txn"/> is null, but
117         /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will
118         /// be implicitly transaction protected. Note that transactionally
119         /// protected operations on a datbase object requires the object itself
120         /// be transactionally protected during its open. Also note that the
121         /// transaction must be committed before the object is closed.
122         /// </para>
123         /// </remarks>
124         /// <param name="Filename">
125         /// The name of an underlying file that will be used to back the
126         /// database. In-memory databases never intended to be preserved on disk
127         /// may be created by setting this parameter to null.
128         /// </param>
129         /// <param name="cfg">The database's configuration</param>
130         /// <param name="txn">
131         /// If the operation is part of an application-specified transaction,
132         /// <paramref name="txn"/> is a Transaction object returned from
133         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
134         /// the operation is part of a Berkeley DB Concurrent Data Store group,
135         /// <paramref name="txn"/> is a handle returned from
136         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
137         /// </param>
138         /// <returns>A new, open database object</returns>
Open( string Filename, DatabaseConfig cfg, Transaction txn)139         public static Database Open(
140             string Filename, DatabaseConfig cfg, Transaction txn) {
141             return Open(Filename, null, cfg, txn);
142         }
143         /// <summary>
144         /// Instantiate a new Database object and open the database represented
145         /// by <paramref name="Filename"/> and <paramref name="DatabaseName"/>.
146         /// The file specified by <paramref name="Filename"/> must exist.
147         /// </summary>
148         /// <remarks>
149         /// <para>
150         /// If both <paramref name="Filename"/> and
151         /// <paramref name="DatabaseName"/> are null, the database is strictly
152         /// temporary and cannot be opened by any other thread of control, thus
153         /// the database can only be accessed by sharing the single database
154         /// object that created it, in circumstances where doing so is safe. If
155         /// <paramref name="Filename"/> is null and
156         /// <paramref name="DatabaseName"/> is non-null, the database can be
157         /// opened by other threads of control and will be replicated to client
158         /// sites in any replication group.
159         /// </para>
160         /// <para>
161         /// If <paramref name="txn"/> is null, but
162         /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation will
163         /// be implicitly transaction protected. Note that transactionally
164         /// protected operations on a datbase object requires the object itself
165         /// be transactionally protected during its open. Also note that the
166         /// transaction must be committed before the object is closed.
167         /// </para>
168         /// </remarks>
169         /// <param name="Filename">
170         /// The name of an underlying file that will be used to back the
171         /// database. In-memory databases never intended to be preserved on disk
172         /// may be created by setting this parameter to null.
173         /// </param>
174         /// <param name="DatabaseName">
175         /// This parameter allows applications to have multiple databases in a
176         /// single file. Although no DatabaseName needs to be specified, it is
177         /// an error to attempt to open a second database in a file that was not
178         /// initially created using a database name.
179         /// </param>
180         /// <param name="cfg">The database's configuration</param>
181         /// <param name="txn">
182         /// If the operation is part of an application-specified transaction,
183         /// <paramref name="txn"/> is a Transaction object returned from
184         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
185         /// the operation is part of a Berkeley DB Concurrent Data Store group,
186         /// <paramref name="txn"/> is a handle returned from
187         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
188         /// </param>
189         /// <returns>A new, open database object</returns>
Open(string Filename, string DatabaseName, DatabaseConfig cfg, Transaction txn)190         public static new Database Open(string Filename,
191             string DatabaseName, DatabaseConfig cfg, Transaction txn) {
192             Database ret;
193             BaseDatabase db = BaseDatabase.Open(
194                 Filename, DatabaseName, cfg, txn);
195             switch (db.Type.getDBTYPE()) {
196                 case DBTYPE.DB_BTREE:
197                     ret = new BTreeDatabase(db);
198                     break;
199                 case DBTYPE.DB_HASH:
200                     ret = new HashDatabase(db);
201                     break;
202                 case DBTYPE.DB_HEAP:
203                     ret = new HeapDatabase(db);
204                     break;
205                 case DBTYPE.DB_QUEUE:
206                     ret = new QueueDatabase(db);
207                     break;
208                 case DBTYPE.DB_RECNO:
209                     ret = new RecnoDatabase(db);
210                     break;
211                 default:
212                     throw new DatabaseException(0);
213             }
214             db.Dispose();
215             ret.isOpen = true;
216             return ret;
217         }
218         #endregion Constructor
219 
writeToFile(TextWriter OutputStream, string data)220         private static int writeToFile(TextWriter OutputStream, string data) {
221             OutputStream.Write(data);
222             return 0;
223         }
224 
225         #region Methods
226         /// <summary>
227         /// If a key/data pair in the database matches <paramref name="key"/>
228         /// and <paramref name="data"/>, return the key and all duplicate data
229         /// items.
230         /// </summary>
231         /// <param name="key">The key to search for</param>
232         /// <param name="data">The data to search for</param>
233         /// <exception cref="NotFoundException">
234         /// A NotFoundException is thrown if <paramref name="key"/> and
235         /// <paramref name="data"/> are not in the database.
236         /// </exception>
237         /// <exception cref="KeyEmptyException">
238         /// A KeyEmptyException is thrown if the database is a
239         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
240         /// database and <paramref name="key"/> exists, but was never explicitly
241         /// created by the application or was later deleted.
242         /// </exception>
243         /// <returns>
244         /// A <see cref="KeyValuePair{T,T}"/>
245         /// whose Key parameter is <paramref name="key"/> and whose Value
246         /// parameter is the retrieved data items.
247         /// </returns>
248         public
GetBothMultiple( DatabaseEntry key, DatabaseEntry data)249             KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple(
250             DatabaseEntry key, DatabaseEntry data) {
251             /*
252              * Make sure we pass a buffer that's big enough to hold data.Data
253              * and is a multiple of the page size.  Cache this.Pagesize to avoid
254              * multiple P/Invoke calls.
255              */
256             uint pgsz = Pagesize;
257             uint npgs = (data.size / pgsz) + 1;
258             return GetBothMultiple(key, data, (int)(npgs * pgsz), null, null);
259         }
260         /// <summary>
261         /// If a key/data pair in the database matches <paramref name="key"/>
262         /// and <paramref name="data"/>, return the key and all duplicate data
263         /// items.
264         /// </summary>
265         /// <param name="key">The key to search for</param>
266         /// <param name="data">The data to search for</param>
267         /// <param name="BufferSize">
268         /// The initial size of the buffer to fill with duplicate data items. If
269         /// the buffer is not large enough, it will be automatically resized.
270         /// </param>
271         /// <exception cref="NotFoundException">
272         /// A NotFoundException is thrown if <paramref name="key"/> and
273         /// <paramref name="data"/> are not in the database.
274         /// </exception>
275         /// <exception cref="KeyEmptyException">
276         /// A KeyEmptyException is thrown if the database is a
277         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
278         /// database and <paramref name="key"/> exists, but was never explicitly
279         /// created by the application or was later deleted.
280         /// </exception>
281         /// <returns>
282         /// A <see cref="KeyValuePair{T,T}"/>
283         /// whose Key parameter is <paramref name="key"/> and whose Value
284         /// parameter is the retrieved data items.
285         /// </returns>
286         public
GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize)287             KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple(
288             DatabaseEntry key, DatabaseEntry data, int BufferSize) {
289             return GetBothMultiple(key, data, BufferSize, null, null);
290         }
291         /// <summary>
292         /// If a key/data pair in the database matches <paramref name="key"/>
293         /// and <paramref name="data"/>, return the key and all duplicate data
294         /// items.
295         /// </summary>
296         /// <param name="key">The key to search for</param>
297         /// <param name="data">The data to search for</param>
298         /// <param name="BufferSize">
299         /// The initial size of the buffer to fill with duplicate data items. If
300         /// the buffer is not large enough, it will be automatically resized.
301         /// </param>
302         /// <param name="txn">
303         /// <paramref name="txn"/> is a Transaction object returned from
304         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
305         /// the operation is part of a Berkeley DB Concurrent Data Store group,
306         /// <paramref name="txn"/> is a handle returned from
307         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
308         /// </param>
309         /// <exception cref="NotFoundException">
310         /// A NotFoundException is thrown if <paramref name="key"/> and
311         /// <paramref name="data"/> are not in the database.
312         /// </exception>
313         /// <exception cref="KeyEmptyException">
314         /// A KeyEmptyException is thrown if the database is a
315         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
316         /// database and <paramref name="key"/> exists, but was never explicitly
317         /// created by the application or was later deleted.
318         /// </exception>
319         /// <returns>
320         /// A <see cref="KeyValuePair{T,T}"/>
321         /// whose Key parameter is <paramref name="key"/> and whose Value
322         /// parameter is the retrieved data items.
323         /// </returns>
324         public
GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize, Transaction txn)325             KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple(
326             DatabaseEntry key,
327             DatabaseEntry data, int BufferSize, Transaction txn) {
328             return GetBothMultiple(key, data, BufferSize, txn, null);
329         }
330         /// <summary>
331         /// If a key/data pair in the database matches <paramref name="key"/>
332         /// and <paramref name="data"/>, return the key and all duplicate data
333         /// items.
334         /// </summary>
335         /// <param name="key">The key to search for</param>
336         /// <param name="data">The data to search for</param>
337         /// <param name="BufferSize">
338         /// The initial size of the buffer to fill with duplicate data items. If
339         /// the buffer is not large enough, it will be automatically resized.
340         /// </param>
341         /// <param name="txn">
342         /// <paramref name="txn"/> is a Transaction object returned from
343         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
344         /// the operation is part of a Berkeley DB Concurrent Data Store group,
345         /// <paramref name="txn"/> is a handle returned from
346         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
347         /// </param>
348         /// <param name="info">The locking behavior to use.</param>
349         /// <exception cref="NotFoundException">
350         /// A NotFoundException is thrown if <paramref name="key"/> and
351         /// <paramref name="data"/> are not in the database.
352         /// </exception>
353         /// <exception cref="KeyEmptyException">
354         /// A KeyEmptyException is thrown if the database is a
355         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
356         /// database and <paramref name="key"/> exists, but was never explicitly
357         /// created by the application or was later deleted.
358         /// </exception>
359         /// <returns>
360         /// A <see cref="KeyValuePair{T,T}"/>
361         /// whose Key parameter is <paramref name="key"/> and whose Value
362         /// parameter is the retrieved data items.
363         /// </returns>
364         public
GetBothMultiple( DatabaseEntry key, DatabaseEntry data, int BufferSize, Transaction txn, LockingInfo info)365             KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetBothMultiple(
366             DatabaseEntry key, DatabaseEntry data,
367             int BufferSize, Transaction txn, LockingInfo info) {
368             KeyValuePair<DatabaseEntry, DatabaseEntry> kvp;
369             int datasz = (int)data.Data.Length;
370 
371             for (; ; ) {
372                 byte[] udata = new byte[BufferSize];
373                 Array.Copy(data.Data, udata, datasz);
374                 data.UserData = udata;
375                 data.size = (uint)datasz;
376                 try {
377                     kvp = Get(key, data, txn, info,
378                         DbConstants.DB_MULTIPLE | DbConstants.DB_GET_BOTH);
379                     break;
380                 } catch (MemoryException) {
381                     int sz = (int)data.size;
382                     if (sz > BufferSize)
383                         BufferSize = sz;
384                     else
385                         BufferSize *= 2;
386                 }
387             }
388             MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value);
389             return new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>(
390                 kvp.Key, dbe);
391         }
392 
393         /// <summary>
394         /// Retrieve a key and all duplicate data items from the database.
395         /// </summary>
396         /// <param name="key">The key to search for</param>
397         /// <exception cref="NotFoundException">
398         /// A NotFoundException is thrown if <paramref name="key"/> is not in
399         /// the database.
400         /// </exception>
401         /// <exception cref="KeyEmptyException">
402         /// A KeyEmptyException is thrown if the database is a
403         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
404         /// database and <paramref name="key"/> exists, but was never explicitly
405         /// created by the application or was later deleted.
406         /// </exception>
407         /// <returns>
408         /// A <see cref="KeyValuePair{T,T}"/>
409         /// whose Key parameter is <paramref name="key"/> and whose Value
410         /// parameter is the retrieved data items.
411         /// </returns>
GetMultiple( DatabaseEntry key)412         public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple(
413             DatabaseEntry key) {
414             return GetMultiple(key, (int)Pagesize, null, null);
415         }
416         /// <summary>
417         /// Retrieve a key and all duplicate data items from the database.
418         /// </summary>
419         /// <param name="key">The key to search for</param>
420         /// <param name="BufferSize">
421         /// The initial size of the buffer to fill with duplicate data items. If
422         /// the buffer is not large enough, it will be automatically resized.
423         /// </param>
424         /// <exception cref="NotFoundException">
425         /// A NotFoundException is thrown if <paramref name="key"/> is not in
426         /// the database.
427         /// </exception>
428         /// <exception cref="KeyEmptyException">
429         /// A KeyEmptyException is thrown if the database is a
430         /// <see cref="QueueDatabase"/> or <see cref="RecnoDatabase"/>
431         /// database and <paramref name="key"/> exists, but was never explicitly
432         /// created by the application or was later deleted.
433         /// </exception>
434         /// <returns>
435         /// A <see cref="KeyValuePair{T,T}"/>
436         /// whose Key parameter is <paramref name="key"/> and whose Value
437         /// parameter is the retrieved data items.
438         /// </returns>
GetMultiple( DatabaseEntry key, int BufferSize)439         public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple(
440             DatabaseEntry key, int BufferSize) {
441             return GetMultiple(key, BufferSize, null, null);
442         }
443         /// <summary>
444         /// Retrieve a key and all duplicate data items from the database.
445         /// </summary>
446         /// <param name="key">The key to search for</param>
447         /// <param name="BufferSize">
448         /// The initial size of the buffer to fill with duplicate data items. If
449         /// the buffer is not large enough, it will be automatically resized.
450         /// </param>
451         /// <param name="txn">
452         /// <paramref name="txn"/> is a Transaction object returned from
453         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
454         /// the operation is part of a Berkeley DB Concurrent Data Store group,
455         /// <paramref name="txn"/> is a handle returned from
456         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
457         /// </param>
458         /// <returns>
459         /// A <see cref="KeyValuePair{T,T}"/>
460         /// whose Key parameter is <paramref name="key"/> and whose Value
461         /// parameter is the retrieved data items.
462         /// </returns>
GetMultiple( DatabaseEntry key, int BufferSize, Transaction txn)463         public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple(
464             DatabaseEntry key, int BufferSize, Transaction txn) {
465             return GetMultiple(key, BufferSize, txn, null);
466         }
467         /// <summary>
468         /// Retrieve a key and all duplicate data items from the database.
469         /// </summary>
470         /// <param name="key">The key to search for</param>
471         /// <param name="BufferSize">
472         /// The initial size of the buffer to fill with duplicate data items. If
473         /// the buffer is not large enough, it will be automatically resized.
474         /// </param>
475         /// <param name="txn">
476         /// <paramref name="txn"/> is a Transaction object returned from
477         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
478         /// the operation is part of a Berkeley DB Concurrent Data Store group,
479         /// <paramref name="txn"/> is a handle returned from
480         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
481         /// </param>
482         /// <param name="info">The locking behavior to use.</param>
483         /// <returns>
484         /// A <see cref="KeyValuePair{T,T}"/>
485         /// whose Key parameter is <paramref name="key"/> and whose Value
486         /// parameter is the retrieved data items.
487         /// </returns>
GetMultiple( DatabaseEntry key, int BufferSize, Transaction txn, LockingInfo info)488         public KeyValuePair<DatabaseEntry, MultipleDatabaseEntry> GetMultiple(
489             DatabaseEntry key,
490             int BufferSize, Transaction txn, LockingInfo info) {
491             KeyValuePair<DatabaseEntry, DatabaseEntry> kvp;
492 
493             DatabaseEntry data = new DatabaseEntry();
494             for (; ; ) {
495                 data.UserData = new byte[BufferSize];
496                 try {
497                     kvp = Get(key, data, txn, info, DbConstants.DB_MULTIPLE);
498                     break;
499                 } catch (MemoryException) {
500                     int sz = (int)data.size;
501                     if (sz > BufferSize)
502                         BufferSize = sz;
503                     else
504                         BufferSize *= 2;
505                 }
506             }
507             MultipleDatabaseEntry dbe = new MultipleDatabaseEntry(kvp.Value);
508             return new KeyValuePair<DatabaseEntry, MultipleDatabaseEntry>(
509                 kvp.Key, dbe);
510         }
511 
512         /// <summary>
513         /// Create a specialized join cursor for use in performing equality or
514         /// natural joins on secondary indices.
515         /// </summary>
516         /// <remarks>
517         /// <para>
518         /// Once the cursors have been passed as part of <paramref name="lst"/>,
519         /// they should not be accessed or modified until the newly created
520         /// <see cref="JoinCursor"/>has been closed, or else inconsistent
521         /// results may be returned.
522         /// </para>
523         /// <para>
524         /// Joined values are retrieved by doing a sequential iteration over the
525         /// first cursor in <paramref name="lst"/>, and a nested iteration over
526         /// each secondary cursor in the order they are specified in the
527         /// curslist parameter. This requires database traversals to search for
528         /// the current datum in all the cursors after the first. For this
529         /// reason, the best join performance normally results from sorting the
530         /// cursors from the one that refers to the least number of data items
531         /// to the one that refers to the most.
532         /// </para>
533         /// </remarks>
534         /// <param name="lst">
535         /// An array of SecondaryCursors. Each cursor must have been initialized
536         /// to refer to the key on which the underlying database should be
537         /// joined.
538         /// </param>
539         /// <param name="sortCursors">
540         /// If true, sort the cursors from the one that refers to the least
541         /// number of data items to the one that refers to the most.  If the
542         /// data are structured so that cursors with many data items also share
543         /// many common elements, higher performance will result from listing
544         /// those cursors before cursors with fewer data items; that is, a sort
545         /// order other than the default. A setting of false permits
546         /// applications to perform join optimization prior to calling Join.
547         /// </param>
548         /// <returns>
549         /// A specialized join cursor for use in performing equality or natural
550         /// joins on secondary indices.
551         /// </returns>
Join(SecondaryCursor[] lst, bool sortCursors)552         public JoinCursor Join(SecondaryCursor[] lst, bool sortCursors) {
553             int i;
554             IntPtr[] cursList = new IntPtr[lst.Length + 1];
555             for (i = 0; i < lst.Length; i++)
556                 cursList[i] = DBC.getCPtr(
557                     SecondaryCursor.getDBC(lst[i])).Handle;
558             cursList[i] = IntPtr.Zero;
559             return new JoinCursor(db.join(cursList,
560                 sortCursors ? 0 : DbConstants.DB_JOIN_NOSORT));
561         }
562 
563         /// <summary>
564         /// Store multiple data items using keys from the buffer to which the
565         /// key parameter refers and data values from the buffer to which the
566         /// data parameter refers. A successful bulk operation is logically
567         /// equivalent to a loop through each key/data pair, performing a Put
568         /// for each one.
569         /// </summary>
570         /// <remarks>
571         ///
572         /// </remarks>
573         /// <param name="key">Multiple key/data pairs to store in the database
574         /// </param>
Put(MultipleKeyDatabaseEntry key)575         public void Put(MultipleKeyDatabaseEntry key) {
576             Put(key, null, null);
577         }
578 
579         /// <summary>
580         /// Store the key/data pair in the database, replacing any previously
581         /// existing key if duplicates are disallowed, or adding a duplicate
582         /// data item if duplicates are allowed.
583         /// </summary>
584         /// <overloads>
585         /// <para>
586         /// If the database supports duplicates, add the new data value at the
587         /// end of the duplicate set. If the database supports sorted
588         /// duplicates, the new data value is inserted at the correct sorted
589         /// location.
590         /// </para>
591         /// </overloads>
592         /// <param name="key">The key to store in the database</param>
593         /// <param name="data">The data item to store in the database</param>
594         /// <exception cref="DatabaseException">
595         /// Partial put to a duplicate database, or <see cref="QueueDatabase"/>
596         /// or <see cref="RecnoDatabase"/> with fixed-length records.
597         /// </exception>
Put(DatabaseEntry key, DatabaseEntry data)598         public void Put(DatabaseEntry key, DatabaseEntry data) {
599             Put(key, data, null);
600         }
601 
602         /// <summary>
603         /// Store multiple data items using keys from the buffer to which the
604         /// key parameter refers and data values from the buffer to which the
605         /// data parameter refers. A successful bulk operation is logically
606         /// equivalent to a loop through each key/data pair, performing a Put
607         /// for each one.
608         /// </summary>
609         /// <param name="key">Multiple key/data pairs to store in the database
610         /// </param>
611         /// <param name="txn">
612         /// If the operation is part of an application-specified transaction,
613         /// <paramref name="txn"/> is a Transaction object returned from
614         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
615         /// the operation is part of a Berkeley DB Concurrent Data Store group,
616         /// <paramref name="txn"/> is a handle returned from
617         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
618         /// </param>
Put(MultipleKeyDatabaseEntry key, Transaction txn)619         public void Put(MultipleKeyDatabaseEntry key, Transaction txn) {
620             Put(key, null, txn, 0);
621         }
622 
623         /// <summary>
624         /// Store the key/data pair in the database, replacing any previously
625         /// existing key if duplicates are disallowed, or adding a duplicate
626         /// data item if duplicates are allowed.
627         /// </summary>
628         /// <remarks>
629         /// <para>
630         /// When partial put to a duplicate database, a
631         /// <see cref="DatabaseException"/> is thrown.
632         /// </para>
633         /// </remarks>
634         /// <param name="key">The key to store in the database</param>
635         /// <param name="data">The data item to store in the database</param>
636         /// <param name="txn">
637         /// If the operation is part of an application-specified transaction,
638         /// <paramref name="txn"/> is a Transaction object returned from
639         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
640         /// the operation is part of a Berkeley DB Concurrent Data Store group,
641         /// <paramref name="txn"/> is a handle returned from
642         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
643         /// </param>
644         /// <exception cref="DatabaseException">
645         /// Partial put to a duplicate database, or <see cref="QueueDatabase"/>
646         /// or <see cref="RecnoDatabase"/> with fixed-length records.
647         /// </exception>
Put( DatabaseEntry key, DatabaseEntry data, Transaction txn)648         public void Put(
649             DatabaseEntry key, DatabaseEntry data, Transaction txn) {
650             Put(key, data, txn, 0);
651         }
652 
653         /// <summary>
654         /// Store the key/data pairs in the database, only if the key does not
655         /// already appear in the database.
656         /// </summary>
657         /// <param name="key">Key/data pairs to store in the database</param>
PutNoOverwrite(MultipleKeyDatabaseEntry key)658         public void PutNoOverwrite(MultipleKeyDatabaseEntry key) {
659             PutNoOverwrite(key, null, null);
660         }
661 
662         /// <summary>
663         /// Store the key/data pair in the database, only if the key does not
664         /// already appear in the database.
665         /// </summary>
666         /// <remarks>
667         /// This enforcement of uniqueness of keys applies only to the primary
668         /// key, the behavior of insertions into secondary databases is not
669         /// affected. In particular, the insertion of a record that would result
670         /// in the creation of a duplicate key in a secondary database that
671         /// allows duplicates would not be prevented by the use of this flag.
672         /// </remarks>
673         /// <param name="key">The key to store in the database</param>
674         /// <param name="data">The data item to store in the database</param>
PutNoOverwrite(DatabaseEntry key, DatabaseEntry data)675         public void PutNoOverwrite(DatabaseEntry key, DatabaseEntry data) {
676             PutNoOverwrite(key, data, null);
677         }
678 
679         /// <summary>
680         /// Store the key/data pairs in the database, only if the key does not
681         /// already appear in the database.
682         /// </summary>
683         /// <param name="key">Key/data pairs to store in the database</param>
684         /// <param name="txn">
685         /// If the operation is part of an application-specified transaction,
686         /// <paramref name="txn"/> is a Transaction object returned from
687         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
688         /// the operation is part of a Berkeley DB Concurrent Data Store group,
689         /// <paramref name="txn"/> is a handle returned from
690         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
691         /// </param>
PutNoOverwrite( MultipleKeyDatabaseEntry key, Transaction txn)692         public void PutNoOverwrite(
693             MultipleKeyDatabaseEntry key, Transaction txn) {
694             Put(key, null, txn, DbConstants.DB_NOOVERWRITE);
695         }
696 
697         /// <summary>
698         /// Store the key/data pair in the database, only if the key does not
699         /// already appear in the database.
700         /// </summary>
701         /// <remarks>
702         /// This enforcement of uniqueness of keys applies only to the primary
703         /// key, the behavior of insertions into secondary databases is not
704         /// affected. In particular, the insertion of a record that would result
705         /// in the creation of a duplicate key in a secondary database that
706         /// allows duplicates would not be prevented by the use of this flag.
707         /// </remarks>
708         /// <param name="key">The key to store in the database</param>
709         /// <param name="data">The data item to store in the database</param>
710         /// <param name="txn">
711         /// If the operation is part of an application-specified transaction,
712         /// <paramref name="txn"/> is a Transaction object returned from
713         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
714         /// the operation is part of a Berkeley DB Concurrent Data Store group,
715         /// <paramref name="txn"/> is a handle returned from
716         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
717         /// </param>
PutNoOverwrite( DatabaseEntry key, DatabaseEntry data, Transaction txn)718         public void PutNoOverwrite(
719             DatabaseEntry key, DatabaseEntry data, Transaction txn) {
720             Put(key, data, txn, DbConstants.DB_NOOVERWRITE);
721         }
722 
723         /// <summary>
724         /// Protected wrapper for DB->put.  Used by subclasses for access method
725         /// specific operations.
726         /// </summary>
727         /// <param name="key">The key to store in the database</param>
728         /// <param name="data">The data item to store in the database</param>
729         /// <param name="txn">Transaction with which to protect the put</param>
730         /// <param name="flags">Flags to pass to DB->put</param>
Put(DatabaseEntry key, DatabaseEntry data, Transaction txn, uint flags)731         protected void Put(DatabaseEntry key,
732             DatabaseEntry data, Transaction txn, uint flags) {
733             System.Type type = key.GetType();
734             if (type == typeof(MultipleDatabaseEntry))
735                 flags |= DbConstants.DB_MULTIPLE;
736             else if (type == typeof(MultipleKeyDatabaseEntry))
737                 flags |= DbConstants.DB_MULTIPLE_KEY;
738             db.put(Transaction.getDB_TXN(txn), key, data, flags);
739         }
740 
741         /// <summary>
742         /// Write the key/data pairs from all databases in the file to
743         /// <see cref="Console.Out"/>. Key values are written for Btree, Hash
744         /// and Queue databases, but not for Recno databases.
745         /// </summary>
746         /// <param name="file">
747         /// The physical file in which the databases to be salvaged are found.
748         /// </param>
749         /// <param name="cfg">
750         /// Configuration parameters for the databases to be salvaged.
751         /// </param>
Salvage(string file, DatabaseConfig cfg)752         public static void Salvage(string file, DatabaseConfig cfg) {
753             Salvage(file, cfg, false, false, null);
754         }
755         /// <summary>
756         /// Write the key/data pairs from all databases in the file to
757         /// <see cref="Console.Out"/>. Key values are written for Btree, Hash
758         /// and Queue databases, but not for Recno databases.
759         /// </summary>
760         /// <param name="file">
761         /// The physical file in which the databases to be salvaged are found.
762         /// </param>
763         /// <param name="cfg">
764         /// Configuration parameters for the databases to be salvaged.
765         /// </param>
766         /// <param name="Printable">
767         /// If true and characters in either the key or data items are printing
768         /// characters (as defined by isprint(3)), use printing characters to
769         /// represent them. This setting permits users to use standard text
770         /// editors and tools to modify the contents of databases or selectively
771         /// remove data from salvager output.
772         /// </param>
Salvage( string file, DatabaseConfig cfg, bool Printable)773         public static void Salvage(
774             string file, DatabaseConfig cfg, bool Printable) {
775             Salvage(file, cfg, Printable, false, null);
776         }
777         /// <summary>
778         /// Write the key/data pairs from all databases in the file to
779         /// <paramref name="OutputStream"/>. Key values are written for Btree,
780         /// Hash and Queue databases, but not for Recno databases.
781         /// </summary>
782         /// <param name="file">
783         /// The physical file in which the databases to be salvaged are found.
784         /// </param>
785         /// <param name="cfg">
786         /// Configuration parameters for the databases to be salvaged.
787         /// </param>
788         /// <param name="OutputStream">
789         /// The TextWriter to which the databases' key/data pairs are written.
790         /// If null, <see cref="Console.Out"/> will be used.
791         /// </param>
Salvage( string file, DatabaseConfig cfg, TextWriter OutputStream)792         public static void Salvage(
793             string file, DatabaseConfig cfg, TextWriter OutputStream) {
794             Salvage(file, cfg, false, false, OutputStream);
795         }
796         /// <summary>
797         /// Write the key/data pairs from all databases in the file to
798         /// <paramref name="OutputStream"/>. Key values are written for Btree,
799         /// Hash and Queue databases, but not for Recno databases.
800         /// </summary>
801         /// <param name="file">
802         /// The physical file in which the databases to be salvaged are found.
803         /// </param>
804         /// <param name="cfg">
805         /// Configuration parameters for the databases to be salvaged.
806         /// </param>
807         /// <param name="Printable">
808         /// If true and characters in either the key or data items are printing
809         /// characters (as defined by isprint(3)), use printing characters to
810         /// represent them. This setting permits users to use standard text
811         /// editors and tools to modify the contents of databases or selectively
812         /// remove data from salvager output.
813         /// </param>
814         /// <param name="OutputStream">
815         /// The TextWriter to which the databases' key/data pairs are written.
816         /// If null, <see cref="Console.Out"/> will be used.
817         /// </param>
Salvage(string file, DatabaseConfig cfg, bool Printable, TextWriter OutputStream)818         public static void Salvage(string file,
819             DatabaseConfig cfg, bool Printable, TextWriter OutputStream) {
820             Salvage(file, cfg, Printable, false, OutputStream);
821         }
822         /// <summary>
823         /// Write the key/data pairs from all databases in the file to
824         /// <see cref="Console.Out"/>. Key values are written for Btree, Hash
825         /// and Queue databases, but not for Recno databases.
826         /// </summary>
827         /// <param name="file">
828         /// The physical file in which the databases to be salvaged are found.
829         /// </param>
830         /// <param name="cfg">
831         /// Configuration parameters for the databases to be salvaged.
832         /// </param>
833         /// <param name="Printable">
834         /// If true and characters in either the key or data items are printing
835         /// characters (as defined by isprint(3)), use printing characters to
836         /// represent them. This setting permits users to use standard text
837         /// editors and tools to modify the contents of databases or selectively
838         /// remove data from salvager output.
839         /// </param>
840         /// <param name="Aggressive">
841         /// If true, output all the key/data pairs in the file that can be
842         /// found.  Corruption will be assumed and key/data pairs that are
843         /// corrupted or have been deleted may appear in the output (even if the
844         /// file being salvaged is in no way corrupt), and the output will
845         /// almost certainly require editing before being loaded into a
846         /// database.
847         /// </param>
Salvage(string file, DatabaseConfig cfg, bool Printable, bool Aggressive)848         public static void Salvage(string file,
849             DatabaseConfig cfg, bool Printable, bool Aggressive) {
850             Salvage(file, cfg, Printable, Aggressive, null);
851         }
852         /// <summary>
853         /// Write the key/data pairs from all databases in the file to
854         /// <paramref name="OutputStream"/>. Key values are written for Btree,
855         /// Hash and Queue databases, but not for Recno databases.
856         /// </summary>
857         /// <param name="file">
858         /// The physical file in which the databases to be salvaged are found.
859         /// </param>
860         /// <param name="cfg">
861         /// Configuration parameters for the databases to be salvaged.
862         /// </param>
863         /// <param name="Printable">
864         /// If true and characters in either the key or data items are printing
865         /// characters (as defined by isprint(3)), use printing characters to
866         /// represent them. This setting permits users to use standard text
867         /// editors and tools to modify the contents of databases or selectively
868         /// remove data from salvager output.
869         /// </param>
870         /// <param name="Aggressive">
871         /// If true, output all the key/data pairs in the file that can be
872         /// found.  Corruption will be assumed and key/data pairs that are
873         /// corrupted or have been deleted may appear in the output (even if the
874         /// file being salvaged is in no way corrupt), and the output will
875         /// almost certainly require editing before being loaded into a
876         /// database.
877         /// </param>
878         /// <param name="OutputStream">
879         /// The TextWriter to which the databases' key/data pairs are written.
880         /// If null, <see cref="Console.Out"/> will be used.
881         /// </param>
Salvage(string file, DatabaseConfig cfg, bool Printable, bool Aggressive, TextWriter OutputStream)882         public static void Salvage(string file, DatabaseConfig cfg,
883             bool Printable, bool Aggressive, TextWriter OutputStream) {
884             using (Database db = new Database(cfg.Env, 0)) {
885                 db.Config(cfg);
886                 if (OutputStream == null)
887                     OutputStream = Console.Out;
888                 uint flags = DbConstants.DB_SALVAGE;
889                 flags |= Aggressive ? DbConstants.DB_AGGRESSIVE : 0;
890                 flags |= Printable ? DbConstants.DB_PRINTABLE : 0;
891                 writeToFileRef = new BDB_FileWriteDelegate(writeToFile);
892                 db.db.verify(file, null, OutputStream, writeToFileRef, flags);
893             }
894         }
895 
896         /// <summary>
897         /// Upgrade all of the databases included in the file
898         /// <paramref name="file"/>, if necessary. If no upgrade is necessary,
899         /// Upgrade always returns successfully.
900         /// </summary>
901         /// <param name="file">
902         /// The physical file containing the databases to be upgraded.
903         /// </param>
904         /// <param name="cfg">
905         /// Configuration parameters for the databases to be upgraded.
906         /// </param>
Upgrade(string file, DatabaseConfig cfg)907         public static void Upgrade(string file, DatabaseConfig cfg) {
908             Upgrade(file, cfg, false);
909         }
910         /// <summary>
911         /// Upgrade all of the databases included in the file
912         /// <paramref name="file"/>, if necessary. If no upgrade is necessary,
913         /// Upgrade always returns successfully.
914         /// </summary>
915         /// <overloads>
916         /// Database upgrades are done in place and are destructive. For
917         /// example, if pages need to be allocated and no disk space is
918         /// available, the database may be left corrupted. Backups should be
919         /// made before databases are upgraded. See Upgrading databases in the
920         /// Programmer's Reference Guide for more information.
921         /// </overloads>
922         /// <remarks>
923         /// <para>
924         /// As part of the upgrade from the Berkeley DB 3.0 release to the 3.1
925         /// release, the on-disk format of duplicate data items changed. To
926         /// correctly upgrade the format requires applications to specify
927         /// whether duplicate data items in the database are sorted or not.
928         /// Specifying <paramref name="dupSortUpgraded"/> informs Upgrade that
929         /// the duplicates are sorted; otherwise they are assumed to be
930         /// unsorted. Incorrectly specifying the value of this flag may lead to
931         /// database corruption.
932         /// </para>
933         /// <para>
934         /// Further, because this method upgrades a physical file (including all
935         /// the databases it contains), it is not possible to use Upgrade to
936         /// upgrade files in which some of the databases it includes have sorted
937         /// duplicate data items, and some of the databases it includes have
938         /// unsorted duplicate data items. If the file does not have more than a
939         /// single database, if the databases do not support duplicate data
940         /// items, or if all of the databases that support duplicate data items
941         /// support the same style of duplicates (either sorted or unsorted),
942         /// Upgrade will work correctly as long as
943         /// <paramref name="dupSortUpgraded"/> is correctly specified.
944         /// Otherwise, the file cannot be upgraded using Upgrade it must be
945         /// upgraded manually by dumping and reloading the databases.
946         /// </para>
947         /// </remarks>
948         /// <param name="file">
949         /// The physical file containing the databases to be upgraded.
950         /// </param>
951         /// <param name="cfg">
952         /// Configuration parameters for the databases to be upgraded.
953         /// </param>
954         /// <param name="dupSortUpgraded">
955         /// If true, the duplicates in the upgraded database are sorted;
956         /// otherwise they are assumed to be unsorted.  This setting is only
957         /// meaningful when upgrading databases from releases before the
958         /// Berkeley DB 3.1 release.
959         /// </param>
Upgrade( string file, DatabaseConfig cfg, bool dupSortUpgraded)960         public static void Upgrade(
961             string file, DatabaseConfig cfg, bool dupSortUpgraded) {
962             Database db = new Database(cfg.Env, 0);
963             db.Config(cfg);
964             db.db.upgrade(file, dupSortUpgraded ? DbConstants.DB_DUPSORT : 0);
965         }
966 
967         /// <summary>
968         /// Specifies the type of verification to perform
969         /// </summary>
970         public enum VerifyOperation {
971             /// <summary>
972             /// Perform database checks and check sort order
973             /// </summary>
974             DEFAULT,
975             /// <summary>
976             /// Perform the database checks for btree and duplicate sort order
977             /// and for hashing
978             /// </summary>
979             ORDER_CHECK_ONLY,
980             /// <summary>
981             /// Skip the database checks for btree and duplicate sort order and
982             /// for hashing.
983             /// </summary>
984             NO_ORDER_CHECK
985         };
986         /// <summary>
987         /// Verify the integrity of all databases in the file specified by
988         /// <paramref name="file"/>.
989         /// </summary>
990         /// <overloads>
991         /// Verify does not perform any locking, even in Berkeley DB
992         /// environments that are configured with a locking subsystem. As such,
993         /// it should only be used on files that are not being modified by
994         /// another thread of control.
995         /// </overloads>
996         /// <param name="file">
997         /// The physical file in which the databases to be verified are found.
998         /// </param>
999         /// <param name="cfg">
1000         /// Configuration parameters for the databases to be verified.
1001         /// </param>
Verify(string file, DatabaseConfig cfg)1002         public static void Verify(string file, DatabaseConfig cfg) {
1003             Verify(file, null, cfg, VerifyOperation.DEFAULT);
1004         }
1005         /// <summary>
1006         /// Verify the integrity of all databases in the file specified by
1007         /// <paramref name="file"/>.
1008         /// </summary>
1009         /// <remarks>
1010         /// <para>
1011         /// Berkeley DB normally verifies that btree keys and duplicate items
1012         /// are correctly sorted, and hash keys are correctly hashed. If the
1013         /// file being verified contains multiple databases using differing
1014         /// sorting or hashing algorithms, some of them must necessarily fail
1015         /// database verification because only one sort order or hash function
1016         /// can be specified in <paramref name="cfg"/>. To verify files with
1017         /// multiple databases having differing sorting orders or hashing
1018         /// functions, first perform verification of the file as a whole by
1019         /// using <see cref="VerifyOperation.NO_ORDER_CHECK"/>, and then
1020         /// individually verify the sort order and hashing function for each
1021         /// database in the file using
1022         /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>.
1023         /// </para>
1024         /// </remarks>
1025         /// <param name="file">
1026         /// The physical file in which the databases to be verified are found.
1027         /// </param>
1028         /// <param name="cfg">
1029         /// Configuration parameters for the databases to be verified.
1030         /// </param>
1031         /// <param name="op">The extent of verification</param>
Verify( string file, DatabaseConfig cfg, VerifyOperation op)1032         public static void Verify(
1033             string file, DatabaseConfig cfg, VerifyOperation op) {
1034             Verify(file, null, cfg, op);
1035         }
1036         /// <summary>
1037         /// Verify the integrity of the database specified by
1038         /// <paramref name="file"/> and <paramref name="database"/>.
1039         /// </summary>
1040         /// <remarks>
1041         /// <para>
1042         /// Berkeley DB normally verifies that btree keys and duplicate items
1043         /// are correctly sorted, and hash keys are correctly hashed. If the
1044         /// file being verified contains multiple databases using differing
1045         /// sorting or hashing algorithms, some of them must necessarily fail
1046         /// database verification because only one sort order or hash function
1047         /// can be specified in <paramref name="cfg"/>. To verify files with
1048         /// multiple databases having differing sorting orders or hashing
1049         /// functions, first perform verification of the file as a whole by
1050         /// using <see cref="VerifyOperation.NO_ORDER_CHECK"/>, and then
1051         /// individually verify the sort order and hashing function for each
1052         /// database in the file using
1053         /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>.
1054         /// </para>
1055         /// </remarks>
1056         /// <param name="file">
1057         /// The physical file in which the databases to be verified are found.
1058         /// </param>
1059         /// <param name="database">
1060         /// The database in <paramref name="file"/> on which the database checks
1061         /// for btree and duplicate sort order and for hashing are to be
1062         /// performed.  A non-null value for database is only allowed with
1063         /// <see cref="VerifyOperation.ORDER_CHECK_ONLY"/>.
1064         /// </param>
1065         /// <param name="cfg">
1066         /// Configuration parameters for the databases to be verified.
1067         /// </param>
1068         /// <param name="op">The extent of verification</param>
Verify(string file, string database, DatabaseConfig cfg, VerifyOperation op)1069         public static void Verify(string file,
1070             string database, DatabaseConfig cfg, VerifyOperation op) {
1071             using (Database db = new Database(cfg.Env, 0)) {
1072                 db.Config(cfg);
1073                 uint flags;
1074                 switch (op) {
1075                     case VerifyOperation.NO_ORDER_CHECK:
1076                         flags = DbConstants.DB_NOORDERCHK;
1077                         break;
1078                     case VerifyOperation.ORDER_CHECK_ONLY:
1079                         flags = DbConstants.DB_ORDERCHKONLY;
1080                         break;
1081                     case VerifyOperation.DEFAULT:
1082                     default:
1083                         flags = 0;
1084                         break;
1085                 }
1086                 db.db.verify(file, database, null, null, flags);
1087             }
1088         }
1089         #endregion Methods
1090     }
1091 }
1092