DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
DeveelDbConnection.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.Data;
20 using System.Data.Common;
21 
22 using Deveel.Data.Protocol;
23 using Deveel.Data.Sql;
24 using Deveel.Data.Types;
25 
26 namespace Deveel.Data.Client {
27  // TODO:
28  public sealed class DeveelDbConnection : DbConnection {
30 
31  private ConnectionState state;
32  private ConnectionState oldState;
33  private readonly object stateLock = new object();
34 
35  private string serverVersion;
36  private string dataSource;
37 
38  private Dictionary<string, DeveelDbDataReader> openReaders;
39 
41  Client = new ConnectionClient(connector,settings);
42  connectionString = settings;
43  RowCache = new LocalRowCache(this);
44  }
45 
46  private ConnectionClient Client { get; set; }
47 
48  internal LocalRowCache RowCache { get; private set; }
49 
51  if (Transaction != null)
52  throw new DeveelDbException("A transaction is already open on this connection.");
53 
54  if (isolationLevel == IsolationLevel.Unspecified)
55  isolationLevel = IsolationLevel.Serializable;
56 
57  if (isolationLevel != IsolationLevel.Serializable)
58  throw new NotSupportedException(String.Format("Isolation Level '{0}' is not supported yet.", isolationLevel));
59 
60  var commitId = BeginServerTransaction(isolationLevel);
61  return new DeveelDbTransaction(this, isolationLevel, commitId);
62  }
63 
64  protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel) {
65  return BeginTransaction(isolationLevel);
66  }
67 
68  public override void Close() {
69  lock (this) {
70  try {
71  if (State == ConnectionState.Closed)
72  return;
73 
74  if (openReaders != null) {
75  foreach (var reader in openReaders.Values) {
76  reader.Close();
77  }
78 
79  openReaders.Clear();
80  openReaders = null;
81  }
82 
83 
84  if (Transaction != null) {
85  Transaction.Rollback();
86  Transaction = null;
87  }
88 
89  Client.Disconnect();
90  } catch (Exception ex) {
91  throw new DeveelDbException("An error occurred while closing the connection.", ex);
92  } finally {
93  ChangeState(ConnectionState.Closed);
94  }
95  }
96  }
97 
98  public override void ChangeDatabase(string databaseName) {
99  throw new NotImplementedException();
100  }
101 
102  public override void Open() {
103  lock (this) {
104  if (State == ConnectionState.Open)
105  return;
106 
107  if (State != ConnectionState.Closed)
108  return;
109 
110  try {
111  ChangeState(ConnectionState.Connecting);
112 
113  Client.Connect();
114  Client.Authenticate();
115 
116  serverVersion = Client.ServerVersion;
117  } catch (Exception) {
118  ChangeState(ConnectionState.Broken);
119 
120  // TODO: throw a specialized exception
121  throw;
122  }
123 
124  ChangeState(ConnectionState.Open);
125  }
126  }
127 
128  public override string ConnectionString {
129  get { return Settings.ToString(); }
130  set { Settings = new DeveelDbConnectionStringBuilder(value); }
131  }
132 
134  get { return connectionString; }
135  set {
136  AssertClosed();
137  connectionString = value;
138  // TODO: Re-init the connection
139  }
140  }
141 
142  public override string Database {
143  get { return Settings.Database; }
144  }
145 
146  public override ConnectionState State {
147  get {
148  lock (stateLock) {
149  return state;
150  }
151  }
152  }
153 
154  public override string DataSource {
155  get {
156  if (String.IsNullOrEmpty(dataSource)) {
157  if (String.IsNullOrEmpty(connectionString.DataSource) &&
158  !String.IsNullOrEmpty(connectionString.Host)) {
159  dataSource = String.Format("{0}:{1}", connectionString.Host, connectionString.Port);
160  } else {
161  dataSource = connectionString.DataSource;
162  }
163  }
164 
165  return dataSource;
166  }
167  }
168 
169  public override string ServerVersion {
170  get { return serverVersion; }
171  }
172 
173  public override int ConnectionTimeout {
174  get { return Settings.QueryTimeout; }
175  }
176 
177  internal DeveelDbTransaction Transaction { get; set; }
178 
179  protected override DbCommand CreateDbCommand() {
180  return CreateCommand();
181  }
182 
184  return new DeveelDbCommand(this);
185  }
186 
187  private void AssertClosed() {
188  if (state != ConnectionState.Closed)
189  throw new InvalidOperationException("The connection is not closed.");
190  }
191 
192  private void AssertFetching() {
193  if (state != ConnectionState.Fetching)
194  throw new InvalidOperationException("The connection is not fetching data.");
195  }
196 
197  internal void ChangeState(ConnectionState newState) {
198  lock (stateLock) {
199  if (state != newState)
200  OnStateChange(new StateChangeEventArgs(state, newState));
201 
202  oldState = state;
203  state = newState;
204  }
205  }
206 
207  internal void EndState() {
208  ChangeState(oldState);
209  }
210 
211  private int BeginServerTransaction(IsolationLevel isolationLevel) {
212  lock (this) {
213  try {
214  return Client.BeginTransaction(isolationLevel);
215  } catch (Exception ex) {
216  throw new DeveelDbException("Could not begin a transaction.", ex);
217  }
218  }
219  }
220 
221  internal void CommitTransaction(int commitId) {
222  lock (this) {
223  try {
224  Client.CommitTransaction(commitId);
225  } catch (Exception ex) {
226  throw new DeveelDbException(String.Format("Could not COMMIT transaction '{0}' on the server.", commitId), ex);
227  }
228  }
229  }
230 
231  internal void RollbackTransaction(int commitId) {
232  lock (this) {
233  try {
234  Client.RollbackTransaction(commitId);
235  } catch (Exception ex) {
236  throw new DeveelDbException(String.Format("Could not ROLLBACK transaction '{0}' on the server.", commitId), ex);
237  }
238  }
239  }
240 
241  internal IQueryResponse[] ExecuteQuery(int commitId, SqlQuery query) {
242  try {
243  return Client.ExecuteQuery(commitId, query);
244  } catch (Exception ex) {
245  throw new DeveelDbException("An error occurred while executing a query.", ex);
246  }
247  }
248 
249  internal QueryResultPart RequestResultPart(int resultId, int rowIndex, int rowCount) {
250  try {
251  return Client.GetResultPart(resultId, rowIndex, rowCount);
252  } catch (Exception ex) {
253  throw new DeveelDbException(String.Format("Could not retrieve part of the result '{0}' from the server.", resultId), ex);
254  }
255  }
256 
257  internal void DisposeResult(int resultId) {
258  try {
259  Client.DisposeResult(resultId);
260  } catch (Exception ex) {
261  throw new DeveelDbException(String.Format("The remote result '{0}' could not be disposed.", resultId), ex);
262  }
263  }
264 
265  protected override void Dispose(bool disposing) {
266  if (disposing) {
267  Close();
268 
269  if (Client != null)
270  Client.Dispose();
271  }
272 
273  Client = null;
274 
275  base.Dispose(disposing);
276  }
277  }
278 }
Dictionary< string, DeveelDbDataReader > openReaders
DeveelDbConnectionStringBuilder connectionString
A long string in the system.
void ChangeState(ConnectionState newState)
The response to a command executed via the IDatabaseInterface.ExecuteQuery method in the IDatabaseInt...
The default implementation of a database in a system.
Definition: Database.cs:38
Database(DatabaseSystem system, IDatabaseContext context)
Definition: Database.cs:39
override void Dispose(bool disposing)
override void ChangeDatabase(string databaseName)
int BeginServerTransaction(IsolationLevel isolationLevel)
QueryResultPart RequestResultPart(int resultId, int rowIndex, int rowCount)
A cache that stores rows retrieved from the server in result set's.
override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
IQueryResponse[] ExecuteQuery(int commitId, SqlQuery query)
new DeveelDbTransaction BeginTransaction(IsolationLevel isolationLevel)
DeveelDbConnection(IClientConnector connector, DeveelDbConnectionStringBuilder settings)