1 /*-
2  * Copyright (c) 2009, 2020 Oracle and/or its affiliates.  All rights reserved.
3  *
4  * See the file LICENSE for license information.
5  *
6  */
7 using System;
8 using System.Collections.Generic;
9 using System.Text;
10 using BerkeleyDB.Internal;
11 
12 namespace BerkeleyDB {
13     /// <summary>
14     /// A class representing a RecnoDatabase. The Recno format supports fixed-
15     /// or variable-length records, accessed sequentially or by logical record
16     /// number, and optionally backed by a flat text file.
17     /// </summary>
18     public class SecondaryRecnoDatabase : SecondaryDatabase {
19 
20         #region Constructors
SecondaryRecnoDatabase(DatabaseEnvironment env, uint flags)21         internal SecondaryRecnoDatabase(DatabaseEnvironment env, uint flags)
22             : base(env, flags) { }
23 
Config(SecondaryRecnoDatabaseConfig cfg)24         private void Config(SecondaryRecnoDatabaseConfig cfg) {
25             base.Config((SecondaryDatabaseConfig)cfg);
26             db.set_flags(cfg.flags);
27 
28             if (cfg.delimiterIsSet)
29                 db.set_re_delim(cfg.Delimiter);
30             if (cfg.lengthIsSet)
31                 db.set_re_len(cfg.Length);
32             if (cfg.padIsSet)
33                 db.set_re_pad(cfg.PadByte);
34             if (cfg.BackingFile != null)
35                 db.set_re_source(cfg.BackingFile);
36         }
37 
38         /// <summary>
39         /// Instantiate a new SecondaryRecnoDatabase object, open the
40         /// database represented by <paramref name="Filename"/> and associate
41         /// the database with the
42         /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>.
43         /// </summary>
44         /// <remarks>
45         /// <para>
46         /// If <paramref name="Filename"/> is null, the database is strictly
47         /// temporary and cannot be opened by any other thread of control, thus
48         /// the database can only be accessed by sharing the single database
49         /// object that created it, in circumstances where doing so is safe.
50         /// </para>
51         /// <para>
52         /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
53         /// is implicitly transaction protected. Transactionally
54         /// protected operations on a database object requires the object itself
55         /// be transactionally protected during its open.
56         /// </para>
57         /// </remarks>
58         /// <param name="Filename">
59         /// The name of an underlying file used to back the
60         /// database. In-memory databases never intended to be preserved on disk
61         /// may be created by setting this parameter to null.
62         /// </param>
63         /// <param name="cfg">The database's configuration</param>
64         /// <returns>A new, open database object</returns>
Open( string Filename, SecondaryRecnoDatabaseConfig cfg)65         public static SecondaryRecnoDatabase Open(
66             string Filename, SecondaryRecnoDatabaseConfig cfg) {
67             return Open(Filename, null, cfg, null);
68         }
69         /// <summary>
70         /// Instantiate a new SecondaryRecnoDatabase object, open the
71         /// database represented by <paramref name="Filename"/> and associate
72         /// the database with the
73         /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>.
74         /// </summary>
75         /// <remarks>
76         /// <para>
77         /// If both <paramref name="Filename"/> and
78         /// <paramref name="DatabaseName"/> are null, the database is strictly
79         /// temporary and cannot be opened by any other thread of control, thus
80         /// the database can only be accessed by sharing the single database
81         /// object that created it, in circumstances where doing so is safe. If
82         /// <paramref name="Filename"/> is null and
83         /// <paramref name="DatabaseName"/> is non-null, the database can be
84         /// opened by other threads of control and will be replicated to client
85         /// sites in any replication group.
86         /// </para>
87         /// <para>
88         /// If <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
89         /// is implicitly transaction protected. Transactionally
90         /// protected operations on a database object requires the object itself
91         /// be transactionally protected during its open.
92         /// </para>
93         /// </remarks>
94         /// <param name="Filename">
95         /// The name of an underlying file used to back the
96         /// database. In-memory databases never intended to be preserved on disk
97         /// may be created by setting this parameter to null.
98         /// </param>
99         /// <param name="DatabaseName">
100         /// This parameter allows applications to have multiple databases in a
101         /// single file. Although no DatabaseName needs to be specified, it is
102         /// an error to attempt to open a second database in a file that was not
103         /// initially created using a database name.
104         /// </param>
105         /// <param name="cfg">The database's configuration</param>
106         /// <returns>A new, open database object</returns>
Open(string Filename, string DatabaseName, SecondaryRecnoDatabaseConfig cfg)107         public static SecondaryRecnoDatabase Open(string Filename,
108             string DatabaseName, SecondaryRecnoDatabaseConfig cfg) {
109             return Open(Filename, DatabaseName, cfg, null);
110         }
111         /// <summary>
112         /// Instantiate a new SecondaryRecnoDatabase object, open the
113         /// database represented by <paramref name="Filename"/> and associate
114         /// the database with the
115         /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>.
116         /// </summary>
117         /// <remarks>
118         /// <para>
119         /// If <paramref name="Filename"/> is null, the database is strictly
120         /// temporary and cannot be opened by any other thread of control, thus
121         /// the database can only be accessed by sharing the single database
122         /// object that created it, in circumstances where doing so is safe.
123         /// </para>
124         /// <para>
125         /// If <paramref name="txn"/> is null, but
126         /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
127         /// is implicitly transaction protected. Transactionally
128         /// protected operations on a database object requires the object itself
129         /// be transactionally protected during its open. The
130         /// transaction must be committed before the object is closed.
131         /// </para>
132         /// </remarks>
133         /// <param name="Filename">
134         /// The name of an underlying file used to back the
135         /// database. In-memory databases never intended to be preserved on disk
136         /// may be created by setting this parameter to null.
137         /// </param>
138         /// <param name="cfg">The database's configuration</param>
139         /// <param name="txn">
140         /// If the operation is part of an application-specified transaction,
141         /// <paramref name="txn"/> is a Transaction object returned from
142         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
143         /// the operation is part of a Berkeley DB Concurrent Data Store group,
144         /// <paramref name="txn"/> is a handle returned from
145         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
146         /// </param>
147         /// <returns>A new, open database object</returns>
Open(string Filename, SecondaryRecnoDatabaseConfig cfg, Transaction txn)148         public static SecondaryRecnoDatabase Open(string Filename,
149             SecondaryRecnoDatabaseConfig cfg, Transaction txn) {
150             return Open(Filename, null, cfg, txn);
151         }
152         /// <summary>
153         /// Instantiate a new SecondaryRecnoDatabase object, open the
154         /// database represented by <paramref name="Filename"/> and associate
155         /// the database with the
156         /// <see cref="SecondaryDatabaseConfig.Primary">primary index</see>.
157         /// </summary>
158         /// <remarks>
159         /// <para>
160         /// If both <paramref name="Filename"/> and
161         /// <paramref name="DatabaseName"/> are null, the database is strictly
162         /// temporary and cannot be opened by any other thread of control, thus
163         /// the database can only be accessed by sharing the single database
164         /// object that created it, in circumstances where doing so is safe. If
165         /// <paramref name="Filename"/> is null and
166         /// <paramref name="DatabaseName"/> is non-null, the database can be
167         /// opened by other threads of control and will be replicated to client
168         /// sites in any replication group.
169         /// </para>
170         /// <para>
171         /// If <paramref name="txn"/> is null, but
172         /// <see cref="DatabaseConfig.AutoCommit"/> is set, the operation
173         /// is implicitly transaction protected. Transactionally
174         /// protected operations on a database object requires the object itself
175         /// be transactionally protected during its open. The
176         /// transaction must be committed before the object is closed.
177         /// </para>
178         /// </remarks>
179         /// <param name="Filename">
180         /// The name of an underlying file used to back the
181         /// database. In-memory databases never intended to be preserved on disk
182         /// may be created by setting this parameter to null.
183         /// </param>
184         /// <param name="DatabaseName">
185         /// This parameter allows applications to have multiple databases in a
186         /// single file. Although no DatabaseName needs to be specified, it is
187         /// an error to attempt to open a second database in a file that was not
188         /// initially created using a database name.
189         /// </param>
190         /// <param name="cfg">The database's configuration</param>
191         /// <param name="txn">
192         /// If the operation is part of an application-specified transaction,
193         /// <paramref name="txn"/> is a Transaction object returned from
194         /// <see cref="DatabaseEnvironment.BeginTransaction"/>; if
195         /// the operation is part of a Berkeley DB Concurrent Data Store group,
196         /// <paramref name="txn"/> is a handle returned from
197         /// <see cref="DatabaseEnvironment.BeginCDSGroup"/>; otherwise null.
198         /// </param>
199         /// <returns>A new, open database object</returns>
Open(string Filename, string DatabaseName, SecondaryRecnoDatabaseConfig cfg, Transaction txn)200         public static SecondaryRecnoDatabase Open(string Filename,
201             string DatabaseName,
202             SecondaryRecnoDatabaseConfig cfg, Transaction txn) {
203             SecondaryRecnoDatabase ret = new SecondaryRecnoDatabase(cfg.Env, 0);
204             ret.Config(cfg);
205             ret.db.open(Transaction.getDB_TXN(txn), Filename,
206                 DatabaseName, cfg.DbType.getDBTYPE(), cfg.openFlags, 0);
207             ret.isOpen = true;
208             ret.doAssocRef =
209                 new BDB_AssociateDelegate(SecondaryDatabase.doAssociate);
210             cfg.Primary.db.associate(Transaction.getDB_TXN(txn),
211                 ret.db, ret.doAssocRef, cfg.assocFlags);
212 
213             if (cfg.ForeignKeyDatabase != null) {
214                 if (cfg.OnForeignKeyDelete == ForeignKeyDeleteAction.NULLIFY)
215                     ret.doNullifyRef =
216                         new BDB_AssociateForeignDelegate(doNullify);
217                 else
218                     ret.doNullifyRef = null;
219                 cfg.ForeignKeyDatabase.db.associate_foreign(
220                     ret.db, ret.doNullifyRef, cfg.foreignFlags);
221             }
222             return ret;
223         }
224 
225         #endregion Constructors
226 
227         #region Properties
228         /// <summary>
229         /// If true, the logical record numbers are mutable, and change as
230         /// records are added to and deleted from the database.
231         /// </summary>
232         public bool Renumber {
233             get {
234                 uint flags = 0;
235                 db.get_flags(ref flags);
236                 return (flags & DbConstants.DB_RENUMBER) != 0;
237             }
238         }
239         /// <summary>
240         /// If true, any <see cref="BackingFile"/> file is read in its
241         /// entirety when <see cref="Open"/> is called. If false,
242         /// <see cref="BackingFile"/> may be read lazily.
243         /// </summary>
244         public bool Snapshot {
245             get {
246                 uint flags = 0;
247                 db.get_flags(ref flags);
248                 return (flags & DbConstants.DB_SNAPSHOT) != 0;
249             }
250         }
251         /// <summary>
252         /// The delimiting byte used to mark the end of a record in
253         /// <see cref="BackingFile"/>.
254         /// </summary>
255         public int Delimiter {
256             get {
257                 int ret = 0;
258                 db.get_re_delim(ref ret);
259                 return ret;
260             }
261         }
262         /// <summary>
263         /// If using fixed-length, not byte-delimited records, the length of the
264         /// records.
265         /// </summary>
266         public uint Length {
267             get {
268                 uint ret = 0;
269                 db.get_re_len(ref ret);
270                 return ret;
271             }
272         }
273         /// <summary>
274         /// The padding character for short, fixed-length records.
275         /// </summary>
276         public int PadByte {
277             get {
278                 int ret = 0;
279                 db.get_re_pad(ref ret);
280                 return ret;
281             }
282         }
283         /// <summary>
284         /// The underlying source file for the Recno access method.
285         /// </summary>
286         public string BackingFile {
287             get {
288                 string ret = "";
289                 db.get_re_source(out ret);
290                 return ret;
291             }
292         }
293         #endregion Properties
294 
295     }
296 }
297