* roottypes.cs: Rename from tree.cs.
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Firebird / FbConnectionInternal.cs
1 /*
2  *      Firebird ADO.NET Data provider for .NET and Mono 
3  * 
4  *         The contents of this file are subject to the Initial 
5  *         Developer's Public License Version 1.0 (the "License"); 
6  *         you may not use this file except in compliance with the 
7  *         License. You may obtain a copy of the License at 
8  *         http://www.firebirdsql.org/index.php?op=doc&id=idpl
9  *
10  *         Software distributed under the License is distributed on 
11  *         an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
12  *         express or implied. See the License for the specific 
13  *         language governing rights and limitations under the License.
14  * 
15  *      Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16  *      All Rights Reserved.
17  */
18
19 using System;
20 using System.Collections;
21 using System.Data;
22 using System.Text;
23
24 using FirebirdSql.Data.Common;
25 using FirebirdSql.Data.Firebird.DbSchema;
26
27 namespace FirebirdSql.Data.Firebird
28 {
29         internal class FbConnectionInternal : MarshalByRefObject
30         {
31                 #region Fields
32
33                 private IDatabase                       db;
34                 private FbTransaction           activeTransaction;
35                 private ArrayList                       preparedCommands;
36                 private FbConnectionString      options;
37                 private FbConnection            owningConnection;
38                 private long                            created;
39                 private long                            lifetime;
40                 private bool                            pooled;
41
42                 #endregion
43
44                 #region Properties
45
46                 public IDatabase Database
47                 {
48                         get { return this.db; }
49                 }
50
51                 public long Lifetime
52                 {
53                         get { return this.lifetime; }
54                         set { this.lifetime = value; }
55                 }
56
57                 public long Created
58                 {
59                         get { return this.created; }
60                         set { this.created = value; }
61                 }
62
63                 public bool Pooled
64                 {
65                         get { return this.pooled; }
66                         set { this.pooled = value; }
67                 }
68
69                 public bool HasActiveTransaction
70                 {
71                         get
72                         {
73                                 return this.activeTransaction != null && !this.activeTransaction.IsUpdated;
74                         }
75                 }
76
77                 public ArrayList PreparedCommands
78                 {
79                         get
80                         {
81                                 if (this.preparedCommands == null)
82                                 {
83                                         this.preparedCommands = new ArrayList();
84                                 }
85
86                                 return this.preparedCommands;
87                         }
88                 }
89
90                 public FbTransaction ActiveTransaction
91                 {
92                         get { return this.activeTransaction; }
93                 }
94
95                 public FbConnectionString ConnectionOptions
96                 {
97                         get { return this.options; }
98                 }
99
100                 public FbConnection OwningConnection
101                 {
102                         get { return this.owningConnection; }
103                         set { this.owningConnection = value; }
104                 }
105
106                 #endregion
107
108                 #region Constructors
109
110                 public FbConnectionInternal(FbConnectionString options) : this(options, null)
111                 {
112                 }
113
114                 public FbConnectionInternal(FbConnectionString options, FbConnection owningConnection)
115                 {
116                         this.options = options;
117                         this.owningConnection = owningConnection;
118                 }
119
120                 #endregion
121
122                 #region Create and Drop database methods
123
124                 public void CreateDatabase(DatabaseParameterBuffer dpb)
125                 {
126                         IDatabase db = ClientFactory.CreateDatabase(this.options.ServerType);
127                         db.CreateDatabase(dpb, this.options.DataSource, this.options.Port, this.options.Database);
128                 }
129
130                 public void DropDatabase()
131                 {
132                         IDatabase db = ClientFactory.CreateDatabase(this.options.ServerType);
133                         db.Attach(this.BuildDpb(db, this.options), this.options.DataSource, this.options.Port, this.options.Database);
134                         db.DropDatabase();
135                 }
136
137                 #endregion
138
139                 #region Connect and     Disconenct methods
140
141                 public void Connect()
142                 {
143                         try
144                         {
145                                 this.db = ClientFactory.CreateDatabase(this.options.ServerType);
146                                 this.db.Charset = Charset.SupportedCharsets[this.options.Charset];
147                                 this.db.Dialect = this.options.Dialect;
148                                 this.db.PacketSize = this.options.PacketSize;
149
150                                 DatabaseParameterBuffer dpb = this.BuildDpb(this.db, options);
151
152                                 this.db.Attach(dpb, this.options.DataSource, this.options.Port, this.options.Database);
153                         }
154                         catch (IscException ex)
155                         {
156                                 throw new FbException(ex.Message, ex);
157                         }
158                 }
159
160                 public void Disconnect()
161                 {
162                         try
163                         {
164                                 this.db.Dispose();
165
166                                 this.owningConnection   = null;
167                                 this.options                    = null;
168                                 this.lifetime                   = 0;
169                                 this.pooled                             = false;
170                                 this.db                                 = null;
171
172                                 this.DisposePreparedCommands();
173                         }
174                         catch (IscException ex)
175                         {
176                                 throw new FbException(ex.Message, ex);
177                         }
178                 }
179
180                 #endregion
181
182                 #region Transaction     Methods
183
184                 public FbTransaction BeginTransaction(IsolationLevel level, string transactionName)
185                 {
186                         lock (this)
187                         {
188                                 if (this.HasActiveTransaction)
189                                 {
190                                         throw new InvalidOperationException("A transaction is currently active. Parallel transactions are not supported.");
191                                 }
192
193                                 try
194                                 {
195                                         this.activeTransaction = new FbTransaction(this.owningConnection, level);
196                                         this.activeTransaction.BeginTransaction();
197
198                                         if (transactionName != null)
199                                         {
200                                                 this.activeTransaction.Save(transactionName);
201                                         }
202                                 }
203                                 catch (IscException ex)
204                                 {
205                                         throw new FbException(ex.Message, ex);
206                                 }
207                         }
208
209                         return this.activeTransaction;
210                 }
211
212                 public FbTransaction BeginTransaction(FbTransactionOptions options, string transactionName)
213                 {
214                         lock (this)
215                         {
216                                 if (this.HasActiveTransaction)
217                                 {
218                                         throw new InvalidOperationException("A transaction is currently active. Parallel transactions are not supported.");
219                                 }
220
221                                 try
222                                 {
223                                         this.activeTransaction = new FbTransaction(
224                                                 this.owningConnection, IsolationLevel.Unspecified);
225
226                                         this.activeTransaction.BeginTransaction(options);
227
228                                         if (transactionName != null)
229                                         {
230                                                 this.activeTransaction.Save(transactionName);
231                                         }
232                                 }
233                                 catch (IscException ex)
234                                 {
235                                         throw new FbException(ex.Message, ex);
236                                 }
237                         }
238
239                         return this.activeTransaction;
240                 }
241
242                 public void DisposeTransaction()
243                 {
244                         if (this.activeTransaction != null)
245                         {
246                                 this.activeTransaction.Dispose();
247                                 this.activeTransaction = null;
248                         }
249                 }
250
251                 public void TransactionUpdated()
252                 {
253                         for (int i = 0; i < this.PreparedCommands.Count; i++)
254                         {
255                                 FbCommand command = (FbCommand)this.PreparedCommands[i];
256
257                                 if (command.Transaction != null)
258                                 {
259                                         command.CloseReader();
260                                         command.Transaction = null;
261                                 }
262                         }
263                 }
264
265                 #endregion
266
267                 #region Schema Methods
268
269                 public DataTable GetSchema(string collectionName, string[] restrictions)
270                 {
271                         return FbDbSchemaFactory.GetSchema(this.owningConnection, collectionName, restrictions);
272                 }
273
274                 [Obsolete]
275                 public DataTable GetSchema(string collectionName, object[] restrictions)
276                 {
277                         return FbDbSchemaFactory.GetSchema(this.owningConnection, collectionName, restrictions);
278                 }
279
280                 #endregion
281
282                 #region Prepared Commands Methods
283
284                 public void AddPreparedCommand(FbCommand command)
285                 {
286                         if (!this.PreparedCommands.Contains(command))
287                         {
288                                 this.PreparedCommands.Add(command);
289                         }
290                 }
291
292                 public void RemovePreparedCommand(FbCommand command)
293                 {
294                         this.PreparedCommands.Remove(command);
295                 }
296
297                 public void DisposePreparedCommands()
298                 {
299                         if (this.preparedCommands != null)
300                         {
301                                 if (this.PreparedCommands.Count > 0)
302                                 {
303                                         FbCommand[] commands = (FbCommand[])this.PreparedCommands.ToArray(typeof(FbCommand));
304
305                                         for (int i = 0; i < commands.Length; i++)
306                                         {
307                                                 // Release statement handle
308                                                 commands[i].Release();
309                                         }
310                                 }
311
312                                 this.PreparedCommands.Clear();
313                                 this.preparedCommands = null;
314                         }
315                 }
316
317                 #endregion
318
319                 #region Firebird Events Methods
320
321                 public void CloseEventManager()
322                 {
323                         if (this.db.HasRemoteEventSupport)
324                         {
325                                 lock (this.db)
326                                 {
327                                         this.db.CloseEventManager();
328                                 }
329                         }
330                 }
331
332                 #endregion
333
334                 #region Connection Verification
335
336                 public bool Verify()
337                 {
338                         // Do not actually ask for any information
339                         byte[] items = new byte[]
340                         {
341                                 IscCodes.isc_info_end
342                         };
343
344                         try
345                         {
346                                 this.db.GetDatabaseInfo(items, 16);
347
348                                 return true;
349                         }
350                         catch
351                         {
352                                 return false;
353                         }
354                 }
355
356                 #endregion
357
358                 #region Private Methods
359
360                 private DatabaseParameterBuffer BuildDpb(IDatabase db, FbConnectionString options)
361                 {
362                         DatabaseParameterBuffer dpb = db.CreateDatabaseParameterBuffer();
363
364                         dpb.Append(IscCodes.isc_dpb_version1);
365                         dpb.Append(IscCodes.isc_dpb_dummy_packet_interval,
366                                 new byte[] { 120, 10, 0, 0 });
367                         dpb.Append(IscCodes.isc_dpb_sql_dialect,
368                                 new byte[] { Convert.ToByte(options.Dialect), 0, 0, 0 });
369                         dpb.Append(IscCodes.isc_dpb_lc_ctype, options.Charset);
370                         if (options.Role != null && options.Role.Length > 0)
371                         {
372                                 dpb.Append(IscCodes.isc_dpb_sql_role_name, options.Role);
373                         }
374                         dpb.Append(IscCodes.isc_dpb_connect_timeout, options.ConnectionTimeout);
375                         dpb.Append(IscCodes.isc_dpb_user_name, options.UserID);
376                         dpb.Append(IscCodes.isc_dpb_password, options.Password);
377
378                         return dpb;
379                 }
380
381                 #endregion
382         }
383 }