DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
Database.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections.Generic;
19 using System.IO;
20 
21 using Deveel.Data.Diagnostics;
22 using Deveel.Data.Security;
23 using Deveel.Data.Sql;
24 using Deveel.Data.Sql.Schemas;
25 using Deveel.Data.Sql.Tables;
27 
28 namespace Deveel.Data {
38  public sealed class Database : IDatabase {
39  internal Database(DatabaseSystem system, IDatabaseContext context) {
40  System = system;
41  Context = context;
42 
43  Name = Context.DatabaseName();
44 
45  DiscoverDataVersion();
46 
47  TableComposite = new TableSourceComposite(this);
48 
49  Context.RegisterInstance(this);
50  Context.RegisterInstance<ITableSourceComposite>(TableComposite);
51 
52  Locker = new Locker(this);
53 
54  Sessions = new ActiveSessionList(this);
55 
56  // Create the single row table
57  var t = new TemporaryTable(context, "SINGLE_ROW_TABLE", new ColumnInfo[0]);
58  t.NewRow();
59  SingleRowTable = t;
60 
61  TransactionFactory = new DatabaseTransactionFactory(this);
62  }
63 
68  Dispose(false);
69  }
70 
77  public string Name { get; private set; }
78 
79  public DatabaseSystem System { get; private set; }
80 
81  public ActiveSessionList Sessions { get; private set; }
82 
83  public Locker Locker { get; private set; }
84 
89  public ITransactionFactory TransactionFactory { get; private set; }
90 
92  get { return System; }
93  }
94 
96  get { return Context; }
97  }
98 
99  IEnumerable<KeyValuePair<string, object>> IEventSource.Metadata {
100  get {
101  return new Dictionary<string, object> {
103  { KnownEventMetadata.SessionCount, Sessions.Count }
104  };
105  }
106  }
107 
108  private void DiscoverDataVersion() {
109  var dataVerion = Attribute.GetCustomAttribute(typeof (Database).Assembly, typeof (DataVersionAttribute))
111  if (dataVerion != null)
112  Version = dataVerion.Version;
113  }
114 
115  public void Dispose() {
116  Dispose(true);
117  GC.SuppressFinalize(this);
118  }
119 
120  private bool disposed;
121 
122  private void Dispose(bool disposing) {
123  if (!disposed) {
124  if (disposing) {
125  if (IsOpen) {
126  // TODO: Report the error
127  }
128 
129  if (Locker != null)
130  Locker.Reset();
131 
132  if (TableComposite != null)
133  TableComposite.Dispose();
134 
135  if (Context != null)
136  Context.Dispose();
137 
138  if (System != null)
139  System.RemoveDatabase(this);
140  }
141 
142  Locker = null;
143  System = null;
144  TableComposite = null;
145  Context = null;
146  disposed = true;
147  }
148  }
149 
154  public IDatabaseContext Context { get; private set; }
155 
163  public Version Version { get; private set; }
164 
171  public bool Exists {
172  get {
173  if (IsOpen)
174  //throw new Exception("The database is initialized, so no point testing it's existence.");
175  return true;
176 
177  try {
178  return TableComposite.Exists();
179  } catch (IOException e) {
180  throw new Exception("An error occurred while testing database existence.", e);
181  }
182  }
183  }
184 
190  public bool IsOpen { get; private set; }
191 
192  internal TableSourceComposite TableComposite { get; private set; }
193 
198  public ITable SingleRowTable { get; private set; }
199 
200  private void OnDatabaseCreate(IQuery context) {
201  var callbacks = Context.ResolveAllServices<IDatabaseCreateCallback>();
202  if (callbacks != null) {
203  foreach (var callback in callbacks) {
204  try {
205  if (callback != null)
206  callback.OnDatabaseCreate(context);
207  } catch (Exception) {
208  //TODO: Route an error event to the listeners
209  }
210  }
211  }
212  }
213 
240  public void Create(string adminName, string adminPassword) {
241  if (Context.ReadOnly())
242  throw new DatabaseSystemException("Cannot create database in read-only mode.");
243 
244  if (String.IsNullOrEmpty(adminName))
245  throw new ArgumentNullException("adminName");
246  if (String.IsNullOrEmpty(adminPassword))
247  throw new ArgumentNullException("adminPassword");
248 
249  try {
250  // Create the conglomerate
251  TableComposite.Create();
252 
253  using (var session = this.CreateInitialSystemSession()) {
254  using (var context = session.CreateQuery()) {
255  try {
256  session.CurrentSchema(SystemSchema.Name);
257 
258  // Create the schema information tables
259  CreateSchemata(context);
260 
261  // The system tables that are present in every conglomerate.
262  SystemSchema.CreateTables(context);
263  SystemGroups.Create(context);
264 
265  context.CreatePublicUser();
266 
267  // Create the system views
270 
271  this.CreateAdminUser(context, adminName, adminPassword);
272 
273  SetCurrentDataVersion(context);
274 
275  // Set all default system procedures.
276  // TODO: SystemSchema.SetupSystemFunctions(session, username);
277 
278  OnDatabaseCreate(context);
279 
280  try {
281  // Close and commit this transaction.
282  session.Commit();
283  } catch (TransactionException e) {
284  throw new DatabaseSystemException("Could not commit the initial information", e);
285  }
286  } catch (DatabaseSystemException) {
287  throw;
288  } catch (Exception ex) {
289  throw new DatabaseSystemException("An error occurred while creating the database.", ex);
290  }
291  }
292  }
293 
294  // Close the conglomerate.
295  TableComposite.Close();
296  } catch (DatabaseSystemException) {
297  throw;
298  } catch (Exception e) {
299  throw new DatabaseSystemException("An error occurred while creating the database.", e);
300  }
301  }
302 
303  private void SetCurrentDataVersion(IQuery context) {
304  // TODO: Get the data version and then set it to the database table 'vars'
305  }
306 
307  private void CreateSchemata(IQuery context) {
308  try {
309  context.CreateSchema(InformationSchema.SchemaName, SchemaTypes.System);
310  context.CreateSchema(Context.DefaultSchema(), SchemaTypes.Default);
311  } catch (DatabaseSystemException) {
312  throw;
313  } catch (Exception ex) {
314  throw new DatabaseSystemException("Unable to create the default schema for the database.", ex);
315  }
316  }
317 
337  public void Open() {
338  if (IsOpen)
339  throw new DatabaseSystemException("The database was already initialized.");
340 
341  try {
342  // Check if the state file exists. If it doesn't, we need to report
343  // incorrect version.
344  if (!TableComposite.Exists())
345  // If neither store or state file exist, assume database doesn't
346  // exist.
347  throw new DatabaseSystemException(String.Format("The database {0} does not exist.", Name));
348 
349  // Open the conglomerate
350  TableComposite.Open();
351 
352  AssertDataVersion();
353  } catch (DatabaseSystemException) {
354  throw;
355  } catch (Exception e) {
356  throw new DatabaseSystemException("An error occurred when initializing the database.", e);
357  }
358 
359  IsOpen = true;
360  }
361 
362  private void AssertDataVersion() {
363  // TODO:
364  }
365 
378  public void Close() {
379  if (!IsOpen)
380  throw new DatabaseSystemException("The database is not initialized.");
381 
382  try {
383  if (Context.DeleteOnClose()) {
384  // Delete the tables if the database is set to delete on
385  // shutdown.
386  TableComposite.Delete();
387  } else {
388  // Otherwise close the conglomerate.
389  TableComposite.Close();
390  }
391  } catch (DatabaseSystemException) {
392  throw;
393  } catch (Exception e) {
394  throw new DatabaseSystemException("An error occurred during database shutdown.", e);
395  } finally {
396  IsOpen = false;
397  }
398  }
399 
400  #region DatabaseTransactionFactory
401 
403  private readonly Database database;
404 
406  this.database = database;
407  OpenTransactions = new TransactionCollection();
408  }
409 
410  public TransactionCollection OpenTransactions { get; private set; }
411 
413  lock (this) {
414  ITransaction transaction;
415 
416  try {
417  transaction = database.TableComposite.CreateTransaction(isolation);
418  } catch (DatabaseSystemException) {
419  throw;
420  } catch (Exception ex) {
421  throw new DatabaseSystemException("Unable to create a transaction.", ex);
422  }
423 
424  return transaction;
425  }
426  }
427  }
428 
429  #endregion
430  }
431 }
Defines the metadata properties of a column within a table of a database.
Definition: ColumnInfo.cs:36
Defines the contract to access the data contained into a table of a database.
Definition: ITable.cs:40
static void CreateTables(IQuery context)
void AssertDataVersion()
Definition: Database.cs:362
Defines the callback that a IDatabase.Create function calls right before the finalization of the data...
The context of a single database within a system.
Defines the required features to factory transactions within a relational system. ...
~Database()
Finalizes an instance of the Database class.
Definition: Database.cs:67
void OnDatabaseCreate(IQuery context)
Definition: Database.cs:200
virtual void Dispose(bool disposing)
Definition: Context.cs:63
void Close()
Closes the database making it not accessible to connections.
Definition: Database.cs:378
The default implementation of a database in a system.
Definition: Database.cs:38
Exception thrown where various problems occur within the database.
Database(DatabaseSystem system, IDatabaseContext context)
Definition: Database.cs:39
void SetCurrentDataVersion(IQuery context)
Definition: Database.cs:303
The representation of a single database in the system.
Definition: IDatabase.cs:40
Manages all the open sessions towards a single database within as system.
IEventSource ParentSource
Gets an optional parent source.
Definition: IEventSource.cs:49
IEnumerable< KeyValuePair< string, object > > Metadata
Gets the list of metadata associated to the source.
Definition: IEventSource.cs:57
void Dispose(bool disposing)
Definition: Database.cs:122
void CreateSchemata(IQuery context)
Definition: Database.cs:307
void Create(string adminName, string adminPassword)
Creates the database in the context given, granting the administrative control to the user identified...
Definition: Database.cs:240
void Open()
Opens the database making it ready to be accessed.
Definition: Database.cs:337
Provides utilities and properties for handling the SYSTEN schema of a database.
Definition: SystemSchema.cs:37
ITransaction CreateTransaction(IsolationLevel isolation)
Creates a new the transaction with the isolation specified.
Definition: Database.cs:412
void OnDatabaseCreate(IQuery context)
Called when the database is created and before the finalization of the initialization process...
const string Name
The name of the system schema that contains tables referring to system information.
static void Create(IQuery context)
Definition: SystemGroups.cs:57
The simplest implementation of a transaction.
Definition: ITransaction.cs:30
void DiscoverDataVersion()
Definition: Database.cs:108
Represents the origin of system events, providing a mechanism to fill the metadata before dispatching...
Definition: IEventSource.cs:40