2 * Firebird ADO.NET Data provider for .NET and Mono
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
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.
15 * Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16 * All Rights Reserved.
20 using System.Collections;
21 using System.ComponentModel;
24 using System.Globalization;
27 using FirebirdSql.Data.Common;
29 namespace FirebirdSql.Data.Firebird
31 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/overview/*'/>
34 [ToolboxBitmap(typeof(FbConnection), "Resources.FbConnection.bmp")]
35 [DefaultEvent("InfoMessage")]
37 public sealed class FbConnection : Component, IDbConnection, ICloneable
41 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/event[@name="StateChange"]/*'/>
42 public event StateChangeEventHandler StateChange;
44 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/event[@name="InfoMessage"]/*'/>
45 public event FbInfoMessageEventHandler InfoMessage;
51 private FbConnectionInternal innerConnection;
52 private ConnectionState state;
53 private FbConnectionString options;
54 private bool disposed;
55 private string connectionString;
61 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="ConnectionString"]/*'/>
63 [Category("Data"), RecommendedAsConfigurableAttribute(true), RefreshProperties(RefreshProperties.All), DefaultValue("")]
64 [Editor(typeof(Design.FbConnectionStringUIEditor), typeof(System.Drawing.Design.UITypeEditor))]
66 public string ConnectionString
68 get { return this.connectionString; }
73 if (this.state == ConnectionState.Closed)
80 this.options.Load(value);
81 this.options.Validate();
82 this.connectionString = value;
88 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="ConnectionTimeout"]/*'/>
90 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
92 public int ConnectionTimeout
94 get { return this.options.ConnectionTimeout; }
97 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="Database"]/*'/>
99 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
101 public string Database
103 get { return this.options.Database; }
106 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="DataSource"]/*'/>
108 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
110 public string DataSource
112 get { return this.options.DataSource; }
115 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="ServerVersion"]/*'/>
117 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
119 public string ServerVersion
123 if (this.state == ConnectionState.Closed)
125 throw new InvalidOperationException("The connection is closed.");
128 if (this.innerConnection != null)
130 return this.innerConnection.Database.ServerVersion;
137 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="State"]/*'/>
139 [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
141 public ConnectionState State
143 get { return this.state; }
146 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="PacketSize"]/*'/>
148 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
150 public int PacketSize
152 get { return this.options.PacketSize; }
157 #region Internal Properties
159 internal FbConnectionInternal InnerConnection
161 get { return this.innerConnection; }
164 internal FbConnectionString ConnectionOptions
166 get { return this.options; }
169 internal bool IsClosed
171 get { return this.state == ConnectionState.Closed; }
178 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/constructor[@name="ctor"]/*'/>
179 public FbConnection() : this(null)
183 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/constructor[@name="ctor(System.String)"]/*'/>
184 public FbConnection(string connectionString) : base()
186 this.options = new FbConnectionString();
187 this.state = ConnectionState.Closed;
188 this.connectionString = "";
190 if (connectionString != null)
192 this.ConnectionString = connectionString;
198 #region IDisposable Methods
200 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="Dispose(System.Boolean)"]/*'/>
201 protected override void Dispose(bool disposing)
209 // release any unmanaged resources
214 // release any managed resources
215 this.innerConnection = null;
218 this.disposed = true;
225 base.Dispose(disposing);
233 #region ICloneable Methods
235 object ICloneable.Clone()
237 return new FbConnection(this.ConnectionString);
242 #region Static Properties
244 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/property[@name="ConnectionPoolsCount"]/*'/>
245 public static int ConnectionPoolsCount
247 get { return FbPoolManager.Instance.PoolsCount; }
252 #region Static Methods
254 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="GetPooledConnectionCount(FbConnection)"]/*'/>
255 public static int GetPooledConnectionCount(FbConnection connection)
257 FbPoolManager manager = FbPoolManager.Instance;
258 FbConnectionPool pool = manager.FindPool(connection.ConnectionString);
268 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="ClearAllPools"]/*'/>
269 public static void ClearAllPools()
271 FbPoolManager manager = FbPoolManager.Instance;
273 manager.ClearAllPools();
276 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="ClearPool(FbConnection)"]/*'/>
277 public static void ClearPool(FbConnection connection)
279 FbPoolManager manager = FbPoolManager.Instance;
281 manager.ClearPool(connection.ConnectionString);
284 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="CreateDatabase(System.String)"]/*'/>
285 public static void CreateDatabase(string connectionString)
287 FbConnection.CreateDatabase(connectionString, 4096, true, false);
290 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="CreateDatabase(System.String, System.Boolean)"]/*'/>
291 public static void CreateDatabase(string connectionString, bool overwrite)
293 FbConnection.CreateDatabase(connectionString, 4096, true, overwrite);
296 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="CreateDatabase(System.String,System.Int32,System.Boolean,System.Boolean)"]/*'/>
297 public static void CreateDatabase(
298 string connectionString, int pageSize, bool forcedWrites, bool overwrite)
300 FbConnectionString options = new FbConnectionString(connectionString);
306 DatabaseParameterBuffer dpb = new DatabaseParameterBuffer();
309 dpb.Append(IscCodes.isc_dpb_version1);
311 // Dummy packet interval
312 dpb.Append(IscCodes.isc_dpb_dummy_packet_interval, new byte[] { 120, 10, 0, 0 });
315 dpb.Append(IscCodes.isc_dpb_user_name, options.UserID);
318 dpb.Append(IscCodes.isc_dpb_password, options.Password);
321 dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { options.Dialect, 0, 0, 0 });
323 // Database overwrite
324 dpb.Append(IscCodes.isc_dpb_overwrite, (short)(overwrite ? 1 : 0));
327 if (options.Charset.Length > 0)
329 int index = Charset.SupportedCharsets.IndexOf(options.Charset);
333 throw new ArgumentException("Character set is not valid.");
338 IscCodes.isc_dpb_set_db_charset,
339 Charset.SupportedCharsets[index].Name);
346 dpb.Append(IscCodes.isc_dpb_page_size, pageSize);
350 dpb.Append(IscCodes.isc_dpb_force_write, (short)(forcedWrites ? 1 : 0));
354 // Check if the database exists
355 FbConnectionInternal c = new FbConnectionInternal(options);
362 IscException ex = new IscException(IscCodes.isc_db_or_file_exists);
363 throw new FbException(ex.Message, ex);
365 catch (FbException ex)
367 if (ex.ErrorCode != 335544344)
374 // Create the new database
375 FbConnectionInternal db = new FbConnectionInternal(options);
376 db.CreateDatabase(dpb);
378 catch (IscException ex)
380 throw new FbException(ex.Message, ex);
384 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="DropDatabase(System.String)"]/*'/>
385 public static void DropDatabase(string connectionString)
387 // Configure Attachment
388 FbConnectionString options = new FbConnectionString(connectionString);
394 FbConnectionInternal db = new FbConnectionInternal(options);
397 catch (IscException ex)
399 throw new FbException(ex.Message, ex);
403 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="CreateDatabase(System.Collections.Hashtable)"]/*'/>
404 [Obsolete("Use CreateDatabase(string connectionString) instead")]
405 public static void CreateDatabase(Hashtable values)
407 bool overwrite = false;
412 if (!values.ContainsKey("User") ||
413 !values.ContainsKey("Password") ||
414 !values.ContainsKey("Database"))
416 throw new ArgumentException("CreateDatabase requires a user name, password and database path.");
419 if (values.ContainsKey("ServerType"))
421 serverType = Convert.ToInt32(values["ServerType"], CultureInfo.InvariantCulture);
424 if (!values.ContainsKey("DataSource"))
426 values.Add("DataSource", "localhost");
429 if (!values.ContainsKey("Port"))
431 values.Add("Port", 3050);
434 if (values.ContainsKey("Dialect"))
436 dialect = Convert.ToByte(values["Dialect"], CultureInfo.InvariantCulture);
439 if (dialect < 1 || dialect > 3)
441 throw new ArgumentException("Incorrect database dialect it should be 1, 2, or 3.");
444 if (values.ContainsKey("Overwrite"))
446 overwrite = (bool)values["Overwrite"];
451 // Configure Attachment
452 FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
454 csb.DataSource = values["DataSource"].ToString();
455 csb.UserID = values["User"].ToString();
456 csb.Password = values["Password"].ToString();
457 csb.Database = values["Database"].ToString();
458 csb.Port = Convert.ToInt32(values["Port"], CultureInfo.InvariantCulture);
459 csb.ServerType = serverType;
461 FbConnectionString options = new FbConnectionString(csb);
464 DatabaseParameterBuffer dpb = new DatabaseParameterBuffer();
467 dpb.Append(IscCodes.isc_dpb_version1);
469 // Dummy packet interval
470 dpb.Append(IscCodes.isc_dpb_dummy_packet_interval, new byte[] { 120, 10, 0, 0 });
473 dpb.Append(IscCodes.isc_dpb_user_name, values["User"].ToString());
476 dpb.Append(IscCodes.isc_dpb_password, values["Password"].ToString());
479 dpb.Append(IscCodes.isc_dpb_sql_dialect, new byte[] { dialect, 0, 0, 0 });
481 // Database overwrite
482 dpb.Append(IscCodes.isc_dpb_overwrite, (short)(overwrite ? 1 : 0));
485 if (values.ContainsKey("Charset"))
487 index = Charset.SupportedCharsets.IndexOf(values["Charset"].ToString());
491 throw new ArgumentException("Character set is not valid.");
496 IscCodes.isc_dpb_set_db_charset,
497 Charset.SupportedCharsets[index].Name);
502 if (values.ContainsKey("PageSize"))
504 dpb.Append(IscCodes.isc_dpb_page_size, Convert.ToInt32(values["PageSize"], CultureInfo.InvariantCulture));
508 if (values.ContainsKey("ForcedWrite"))
510 dpb.Append(IscCodes.isc_dpb_force_write,
511 (short)((bool)values["ForcedWrite"] ? 1 : 0));
518 // Check if the database exists
519 FbConnectionInternal check = new FbConnectionInternal(options);
524 IscException ex = new IscException(IscCodes.isc_db_or_file_exists);
526 throw new FbException(ex.Message, ex);
534 // Create the new database
535 FbConnectionInternal c = new FbConnectionInternal(options);
536 c.CreateDatabase(dpb);
538 catch (IscException ex)
540 throw new FbException(ex.Message, ex);
544 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="DropDatabase(System.Collections.Hashtable)"]/*'/>
545 [Obsolete("Use DropDatabase(string connectionString) instead")]
546 public static void DropDatabase(Hashtable values)
550 if (!values.ContainsKey("User") ||
551 !values.ContainsKey("Password") ||
552 !values.ContainsKey("Database"))
554 throw new ArgumentException("CreateDatabase requires a user name, password and database path.");
557 if (!values.ContainsKey("DataSource"))
559 values.Add("DataSource", "localhost");
562 if (!values.ContainsKey("Port"))
564 values.Add("Port", 3050);
567 if (values.ContainsKey("ServerType"))
569 serverType = Convert.ToInt32(values["ServerType"], CultureInfo.InvariantCulture);
574 // Configure Attachment
575 FbConnectionStringBuilder csb = new FbConnectionStringBuilder();
577 csb.DataSource = values["DataSource"].ToString();
578 csb.Port = Convert.ToInt32(values["Port"], CultureInfo.InvariantCulture);
579 csb.Database = values["Database"].ToString();
580 csb.UserID = values["User"].ToString();
581 csb.Password = values["Password"].ToString();
582 csb.ServerType = serverType;
584 FbConnectionString options = new FbConnectionString(csb);
587 FbConnectionInternal db = new FbConnectionInternal(options);
590 catch (IscException ex)
592 throw new FbException(ex.Message, ex);
600 IDbTransaction IDbConnection.BeginTransaction()
602 return this.BeginTransaction();
605 IDbTransaction IDbConnection.BeginTransaction(IsolationLevel level)
607 return this.BeginTransaction(level);
610 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction"]/*'/>
611 public FbTransaction BeginTransaction()
613 return this.BeginTransaction(IsolationLevel.ReadCommitted, null);
616 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction(System.String)"]/*'/>
617 public FbTransaction BeginTransaction(string transactionName)
619 return this.BeginTransaction(IsolationLevel.ReadCommitted, transactionName);
622 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction(System.Data.IsolationLevel)"]/*'/>
623 public FbTransaction BeginTransaction(IsolationLevel level)
625 return this.BeginTransaction(level, null);
628 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction(System.Data.IsolationLevel,System.String)"]/*'/>
629 public FbTransaction BeginTransaction(IsolationLevel level, string transactionName)
633 throw new InvalidOperationException("BeginTransaction requires an open and available Connection.");
636 return this.innerConnection.BeginTransaction(level, transactionName);
639 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction(FbTransactionOptions)"]/*'/>
640 public FbTransaction BeginTransaction(FbTransactionOptions options)
642 return this.BeginTransaction(options, null);
645 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="BeginTransaction(FbTransactionOptions, System.String)"]/*'/>
646 public FbTransaction BeginTransaction(FbTransactionOptions options, string transactionName)
650 throw new InvalidOperationException("BeginTransaction requires an open and available Connection.");
653 return this.innerConnection.BeginTransaction(options, transactionName);
656 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="ChangeDatabase(System.String)"]/*'/>
657 public void ChangeDatabase(string db)
663 throw new InvalidOperationException("ChangeDatabase requires an open and available Connection.");
666 if (db == null || db.Trim().Length == 0)
668 throw new InvalidOperationException("Database name is not valid.");
671 string cs = this.connectionString;
675 FbConnectionStringBuilder csb = new FbConnectionStringBuilder(this.connectionString);
677 // Close current connection
680 // Set up the new Database
683 // Open new connection
686 catch (IscException ex)
688 this.ConnectionString = cs;
689 throw new FbException(ex.Message, ex);
694 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="Open"]/*'/>
699 if (this.connectionString == null || this.connectionString.Length == 0)
701 throw new InvalidOperationException("Connection String is not initialized.");
703 if (!this.IsClosed && this.state != ConnectionState.Connecting)
705 throw new InvalidOperationException("Connection already Open.");
710 this.OnStateChange(this.state, ConnectionState.Connecting);
712 if (this.options.Pooling)
714 // Use Connection Pooling
715 FbConnectionPool pool = FbPoolManager.Instance.CreatePool(this.connectionString);
716 this.innerConnection = pool.CheckOut();
717 this.innerConnection.OwningConnection = this;
721 // Do not use Connection Pooling
722 this.innerConnection = new FbConnectionInternal(this.options, this);
723 this.innerConnection.Connect();
726 // Bind Warning messages event
727 this.innerConnection.Database.WarningMessage = new WarningMessageCallback(this.OnWarningMessage);
729 // Update the connection state
730 this.OnStateChange(this.state, ConnectionState.Open);
732 catch (IscException ex)
734 this.OnStateChange(this.state, ConnectionState.Closed);
735 throw new FbException(ex.Message, ex);
739 this.OnStateChange(this.state, ConnectionState.Closed);
745 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="Close"]/*'/>
757 lock (this.innerConnection)
759 // Close the Remote Event Manager
760 this.innerConnection.CloseEventManager();
762 // Unbind Warning messages event
763 this.innerConnection.Database.WarningMessage = null;
765 // Dispose Transaction
766 this.innerConnection.DisposeTransaction();
768 // Dispose all active statemenets
769 this.innerConnection.DisposePreparedCommands();
771 // Close connection or send it back to the pool
772 if (this.innerConnection.Pooled)
774 // Get Connection Pool
775 FbConnectionPool pool = FbPoolManager.Instance.FindPool(this.connectionString);
777 // Send connection to the Pool
778 pool.CheckIn(this.innerConnection);
782 this.innerConnection.Disconnect();
786 // Update connection state
787 this.OnStateChange(this.state, ConnectionState.Closed);
789 catch (IscException ex)
791 throw new FbException(ex.Message, ex);
796 IDbCommand IDbConnection.CreateCommand()
798 return this.CreateCommand();
801 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="CreateCommand"]/*'/>
802 public FbCommand CreateCommand()
804 FbCommand command = new FbCommand();
808 command.Connection = this;
816 #region Database Schema
818 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="GetSchema"]/*'/>
819 public DataTable GetSchema()
821 return this.GetSchema("MetaDataCollections");
824 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="GetSchema(System.String)"]/*'/>
825 public DataTable GetSchema(string collectionName)
827 return this.GetSchema(collectionName, null);
830 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="GetSchema(System.String, System.String[])"]/*'/>
831 public DataTable GetSchema(string collectionName, string[] restrictions)
835 throw new InvalidOperationException("The connection is closed.");
838 return this.innerConnection.GetSchema(collectionName, restrictions);
841 /// <include file='Doc/en_EN/FbConnection.xml' path='doc/class[@name="FbConnection"]/method[@name="GetDbSchemaTable"]/*'/>
842 [Obsolete("Use GetSchema methods instead")]
843 public DataTable GetDbSchemaTable(FbDbSchemaType schema, object[] restrictions)
845 if (this.state == ConnectionState.Closed)
847 throw new InvalidOperationException("The conneciton is closed.");
850 return innerConnection.GetSchema(schema.ToString(), restrictions);
855 #region Private Methods
857 private void OnWarningMessage(IscException warning)
859 if (this.InfoMessage != null)
861 this.InfoMessage(this, new FbInfoMessageEventArgs(warning));
865 private void OnStateChange(ConnectionState originalState, ConnectionState currentState)
867 this.state = currentState;
868 if (this.StateChange != null)
870 this.StateChange(this, new StateChangeEventArgs(originalState, currentState));