// Copyright (C) 2004-2006 MySQL AB
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as published by
// the Free Software Foundation
//
// There are special exceptions to the terms and conditions of the GPL
// as it is applied to this software. View the full text of the
// exception in file EXCEPTIONS in the directory of this software
// distribution.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
using System;
using System.ComponentModel;
using System.Data.Common;
using MySql.Data.Common;
using System.Globalization;
using System.Collections.Generic;
using System.Text;
namespace MySql.Data.MySqlClient
{
///
public sealed class MySqlConnectionStringBuilder : DbConnectionStringBuilder
{
string userId, password, server;
string database, sharedMemName, pipeName, charSet;
string optionFile;
string originalConnectionString;
StringBuilder persistConnString;
uint port, connectionTimeout, minPoolSize, maxPoolSize;
uint procCacheSize, connectionLifetime;
MySqlConnectionProtocol protocol;
MySqlDriverType driverType;
bool compress, connectionReset, allowBatch, logging;
bool oldSyntax, persistSI, usePerfMon, pooling;
bool allowZeroDatetime, convertZeroDatetime;
bool useUsageAdvisor, useSSL;
bool ignorePrepare;
///
/// Initializes a new instance of the class.
///
public MySqlConnectionStringBuilder()
{
persistConnString = new StringBuilder();
Clear();
}
///
/// Initializes a new instance of the class.
/// The provided connection string provides the data for the instance's internal
/// connection information.
///
/// The basis for the object's internal connection
/// information. Parsed into name/value pairs. Invalid key names raise
/// .
///
public MySqlConnectionStringBuilder(string connectionString)
: base()
{
originalConnectionString = connectionString;
persistConnString = new StringBuilder();
ConnectionString = connectionString;
}
#region Server Properties
///
/// Gets or sets the name of the server.
///
#if !PocketPC && !MONO
[Category("Connection")]
[Description("Server to connect to")]
#endif
public string Server
{
get { return this.server; }
set { CheckNullAndSet("Server", value); server = value; }
}
///
/// Gets or sets the name of the database the connection should
/// initially connect to.
///
#if !PocketPC && !MONO
[Category("Connection")]
[Description("Database to use initially")]
#endif
public string Database
{
get { return this.database; }
set { CheckNullAndSet("Database", value); database = value; }
}
///
/// Gets or sets the protocol that should be used for communicating
/// with MySQL.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Connection Protocol")]
[Description("Protocol to use for connection to MySQL")]
[DefaultValue(MySqlConnectionProtocol.Sockets)]
#endif
public MySqlConnectionProtocol ConnectionProtocol
{
get { return this.protocol; }
set { base["Connection Protocol"] = value.ToString(); protocol = value; }
}
///
/// Gets or sets the name of the named pipe that should be used
/// for communicating with MySQL.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Pipe Name")]
[Description("Name of pipe to use when connecting with named pipes (Win32 only)")]
#endif
public string PipeName
{
get { return this.pipeName; }
set { CheckNullAndSet("Pipe Name", value); pipeName = value; }
}
///
/// Gets or sets a boolean value that indicates whether this connection
/// should use compression.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Use Compression")]
[Description("Should the connection use compression")]
[DefaultValue(false)]
#endif
public bool UseCompression
{
get { return this.compress; }
set { base["use compression"] = value; compress = value; }
}
///
/// Gets or sets a boolean value that indicates whether this connection will allow
/// commands to send multiple SQL statements in one execution.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Allow Batch")]
[Description("Allows execution of multiple SQL commands in a single statement")]
[DefaultValue(true)]
#endif
public bool AllowBatch
{
get { return this.allowBatch; }
set { base["allow batch"] = value; allowBatch = value; }
}
///
/// Gets or sets a boolean value that indicates whether logging is enabled.
///
#if !PocketPC && !MONO
[Category("Connection")]
[Description("Enables output of diagnostic messages")]
[DefaultValue(false)]
#endif
public bool Logging
{
get { return this.logging; }
set { base["logging"] = value; logging = value; }
}
///
/// Gets or sets the base name of the shared memory objects used to
/// communicate with MySQL when the shared memory protocol is being used.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Shared Memory Name")]
[Description("Name of the shared memory object to use")]
[DefaultValue("MYSQL")]
#endif
public string SharedMemoryName
{
get { return this.sharedMemName; }
set { CheckNullAndSet("Shared Memory Name", value); sharedMemName = value; }
}
///
/// Gets or sets a boolean value that indicates whether this connection uses
/// the old style (@) parameter markers or the new (?) style.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Old Syntax")]
[Description("Allows the use of old style @ syntax for parameters")]
[DefaultValue(false)]
#endif
public bool UseOldSyntax
{
get { return this.oldSyntax; }
set { base["Old Syntax"] = value; oldSyntax = value; }
}
///
/// Gets or sets the driver type that should be used for this connection.
///
///
/// There is only one valid value for this setting currently.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Driver Type")]
[Description("Specifies the type of driver to use for this connection")]
[DefaultValue(MySqlDriverType.Native)]
#endif
public MySqlDriverType DriverType
{
get { return this.driverType; }
set { base["Driver Type"] = value; driverType = value; }
}
internal string OptionFile
{
get { return this.optionFile; }
set { CheckNullAndSet("Option File", value); optionFile = value; }
}
///
/// Gets or sets the port number that is used when the socket
/// protocol is being used.
///
#if !PocketPC && !MONO
[Category("Connection")]
[Description("Port to use for TCP/IP connections")]
[DefaultValue(3306)]
#endif
public uint Port
{
get { return this.port; }
set { base["Port"] = value; port = value; }
}
///
/// Gets or sets the connection timeout.
///
#if !PocketPC && !MONO
[Category("Connection")]
[DisplayName("Connection Timeout")]
[Description("The length of time (in seconds) to wait for a connection " +
"to the server before terminating the attempt and generating an error.")]
[DefaultValue(15)]
#endif
public uint ConnectionTimeout
{
get { return this.connectionTimeout; }
set { base["Connection Timeout"] = value; connectionTimeout = value; }
}
#endregion
#region Authentication Properties
///
/// Gets or sets the user id that should be used to connect with.
///
#if !PocketPC && !MONO
[Category("Security")]
[DisplayName("User ID")]
[Description("Indicates the user ID to be used when connecting to the data source.")]
#endif
public string UserID
{
get { return this.userId; }
set { CheckNullAndSet("User Id", value); userId = value; }
}
///
/// Gets or sets the password that should be used to connect with.
///
#if !PocketPC && !MONO
[Category("Security")]
[Description("Indicates the password to be used when connecting to the data source.")]
#endif
public string Password
{
get { return this.password; }
set { CheckNullAndSet("Password", value); password = value; }
}
///
/// Gets or sets a boolean value that indicates if the password should be persisted
/// in the connection string.
///
#if !PocketPC && !MONO
[Category("Security")]
[DisplayName("Persist Security Info")]
[Description("When false, security-sensitive information, such as the password, " +
"is not returned as part of the connection if the connection is open or " +
"has ever been in an open state.")]
#endif
public bool PersistSecurityInfo
{
get { return persistSI; }
set { base["Persist Security Info"] = value; persistSI = value; }
}
#if !PocketPC && !MONO
[Category("Authentication")]
[Description("Should the connection use SSL. This currently has no effect.")]
[DefaultValue(false)]
#endif
internal bool UseSSL
{
get { return useSSL; }
set { base["usessl"] = value; useSSL = value; }
}
#endregion
#region Other Properties
///
/// Gets or sets a boolean value that indicates if zero date time values are supported.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Allow Zero Datetime")]
[Description("Should zero datetimes be supported")]
[DefaultValue(false)]
#endif
public bool AllowZeroDateTime
{
get { return this.allowZeroDatetime; }
set { base["Allow Zero DateTime"] = value; allowZeroDatetime = value; }
}
///
/// Gets or sets a boolean value indicating if zero datetime values should be
/// converted to DateTime.MinValue.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Convert Zero Datetime")]
[Description("Should illegal datetime values be converted to DateTime.MinValue")]
[DefaultValue(false)]
#endif
public bool ConvertZeroDateTime
{
get { return this.convertZeroDatetime; }
set { base["Convert Zero DateTime"] = value; convertZeroDatetime = value; }
}
///
/// Gets or sets the character set that should be used for sending queries to the server.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Character Set")]
[Description("Character set this connection should use")]
#endif
public string CharacterSet
{
get { return this.charSet; }
set { CheckNullAndSet("Character Set", value); charSet = value; }
}
///
/// Gets or sets a boolean value indicating if the Usage Advisor should be enabled.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Use Usage Advisor")]
[Description("Logs inefficient database operations")]
[DefaultValue(false)]
#endif
public bool UseUsageAdvisor
{
get { return useUsageAdvisor; }
set { base["Use Usage Advisor"] = value; useUsageAdvisor = value; }
}
///
/// Gets or sets the size of the stored procedure cache.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Procedure Cache Size")]
[Description("Indicates how many stored procedures can be cached at one time. " +
"A value of 0 effectively disables the procedure cache.")]
[DefaultValue(25)]
#endif
public uint ProcedureCacheSize
{
get { return this.procCacheSize; }
set { base["Procedure Cache Size"] = value; procCacheSize = value; }
}
///
/// Gets or sets a boolean value indicating if the permon hooks should be enabled.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Use Performance Monitor")]
[Description("Indicates that performance counters should be updated during execution.")]
[DefaultValue(false)]
#endif
public bool UsePerformanceMonitor
{
get { return usePerfMon; }
set { base["Use Performance Monitor"] = value; usePerfMon = value; }
}
///
/// Gets or sets a boolean value indicating if calls to Prepare() should be ignored.
///
#if !PocketPC && !MONO
[Category("Advanced")]
[DisplayName("Ignore Prepare")]
[Description("Instructs the provider to ignore any attempts to prepare a command.")]
[DefaultValue(true)]
#endif
public bool IgnorePrepare
{
get { return ignorePrepare; }
set { base["Ignore Prepare"] = value; ignorePrepare = value; }
}
#endregion
#region Pooling Properties
///
/// Gets or sets the lifetime of a pooled connection.
///
#if !PocketPC && !MONO
[Category("Pooling")]
[DisplayName("Connection Lifetime")]
[Description("The minimum amount of time (in seconds) for this connection to " +
"live in the pool before being destroyed.")]
[DefaultValue(0)]
#endif
public uint ConnectionLifeTime
{
get { return connectionLifetime; }
set { base["Connection Lifetime"] = value; connectionLifetime = value; }
}
///
/// Gets or sets a boolean value indicating if connection pooling is enabled.
///
#if !PocketPC && !MONO
[Category("Pooling")]
[Description("When true, the connection object is drawn from the appropriate " +
"pool, or if necessary, is created and added to the appropriate pool.")]
[DefaultValue(true)]
#endif
public bool Pooling
{
get { return pooling; }
set { base["Pooling"] = value; pooling = value; }
}
///
/// Gets the minimum connection pool size.
///
#if !PocketPC && !MONO
[Category("Pooling")]
[DisplayName("Minimum Pool Size")]
[Description("The minimum number of connections allowed in the pool.")]
[DefaultValue(0)]
#endif
public uint MinimumPoolSize
{
get { return minPoolSize; }
set { base["Minimum Pool Size"] = value; minPoolSize = value; }
}
///
/// Gets or sets the maximum connection pool setting.
///
#if !PocketPC && !MONO
[Category("Pooling")]
[DisplayName("Maximum Pool Size")]
[Description("The maximum number of connections allowed in the pool.")]
[DefaultValue(100)]
#endif
public uint MaximumPoolSize
{
get { return maxPoolSize; }
set { base["Maximum Pool Size"] = value; maxPoolSize = value; }
}
///
/// Gets or sets a boolean value indicating if the connection should be reset when retrieved
/// from the pool.
///
#if !PocketPC && !MONO
[Category("Pooling")]
[DisplayName("Connection Reset")]
[Description("When true, indicates the connection state is reset when " +
"removed from the pool.")]
[DefaultValue(true)]
#endif
public bool ConnectionReset
{
get { return connectionReset; }
set { base["Connection Reset"] = value; connectionReset = value; }
}
#endregion
#region Conversion Routines
private void CheckNullAndSet(string keyword, object value)
{
if (value == null)
throw new ArgumentException(Resources.KeywordNoNull, keyword);
base[keyword] = value;
}
private uint ConvertToUInt(object value)
{
try
{
uint uValue = (value as IConvertible).ToUInt32(CultureInfo.InvariantCulture);
return uValue;
}
catch (InvalidCastException)
{
throw new ArgumentException(Resources.ImproperValueFormat, value.ToString());
}
}
private bool ConvertToBool(object value)
{
if (value is string)
{
string s = value.ToString().ToLower();
if (s == "yes" || s == "true") return true;
if (s == "no" || s == "false") return false;
throw new ArgumentException(Resources.ImproperValueFormat, (string)value);
}
else
{
try
{
return (value as IConvertible).ToBoolean(
CultureInfo.InvariantCulture);
}
catch (InvalidCastException)
{
throw new ArgumentException(Resources.ImproperValueFormat, value.ToString());
}
}
}
private MySqlConnectionProtocol ConvertToProtocol(object value)
{
try
{
if (value is string)
return (MySqlConnectionProtocol)Enum.Parse(
typeof(MySqlConnectionProtocol), (value as string), true);
}
catch (Exception)
{
if (value is string)
{
string lowerString = (value as string).ToLower();
if (lowerString == "socket" || lowerString == "tcp")
return MySqlConnectionProtocol.Sockets;
else if (lowerString == "pipe")
return MySqlConnectionProtocol.NamedPipe;
else if (lowerString == "unix")
return MySqlConnectionProtocol.UnixSocket;
else if (lowerString == "memory")
return MySqlConnectionProtocol.SharedMemory;
}
}
throw new ArgumentException(Resources.ImproperValueFormat, value.ToString());
}
private MySqlDriverType ConvertToDriverType(object value)
{
if (value is string)
return (MySqlDriverType)Enum.Parse(
typeof(MySqlDriverType), (value as string), true);
throw new ArgumentException(Resources.ImproperValueFormat, value.ToString());
}
#endregion
#region Private Methods
private void Reset()
{
connectionTimeout = 15;
pooling = true;
port = 3306;
server = String.Empty;
persistSI = false;
connectionLifetime = 0;
connectionReset = false;
minPoolSize = 0;
maxPoolSize = 100;
userId = "";
password = "";
useUsageAdvisor = false;
charSet = "";
compress = false;
pipeName = "MYSQL";
logging = false;
oldSyntax = false;
sharedMemName = "MYSQL";
allowBatch = true;
convertZeroDatetime = false;
database = "";
driverType = MySqlDriverType.Native;
protocol = MySqlConnectionProtocol.Sockets;
allowZeroDatetime = false;
usePerfMon = false;
procCacheSize = 25;
useSSL = false;
ignorePrepare = true;
}
#endregion
///
/// Takes a given connection string and returns it, possible
/// stripping out the password info
///
///
public string GetConnectionString(bool includePass)
{
if (includePass)
return originalConnectionString;
string connStr = persistConnString.ToString();
return connStr.Remove(connStr.Length - 1, 1);
}
///
/// Clears the contents of the instance.
///
public override void Clear()
{
base.Clear();
persistConnString.Remove(0, persistConnString.Length);
Reset();
}
private Keyword GetKey(string key)
{
string lowerKey = key.ToLower();
switch (lowerKey)
{
case "uid":
case "username":
case "user id":
case "user name":
case "userid":
case "user":
return Keyword.UserID;
case "host":
case "server":
case "data source":
case "datasource":
case "address":
case "addr":
case "network address":
return Keyword.Server;
case "password":
case "pwd":
return Keyword.Password;
case "useusageadvisor":
case "usage advisor":
case "use usage advisor":
return Keyword.UseUsageAdvisor;
case "character set":
case "charset":
case "characterset":
return Keyword.CharacterSet;
case "use compression":
case "compress":
case "usecompression":
return Keyword.Compress;
case "pipe name":
case "pipe":
return Keyword.PipeName;
case "logging":
return Keyword.Logging;
case "old syntax":
case "oldsyntax":
case "use old syntax":
return Keyword.OldSyntax;
case "shared memory name":
return Keyword.SharedMemoryName;
case "allow batch":
return Keyword.AllowBatch;
case "convert zero datetime":
case "convertzerodatetime":
return Keyword.ConvertZeroDatetime;
case "persist security info":
return Keyword.PersistSecurityInfo;
case "initial catalog":
case "database":
return Keyword.Database;
case "connection timeout":
case "connect timeout":
return Keyword.ConnectionTimeout;
case "port":
return Keyword.Port;
case "pooling":
return Keyword.Pooling;
case "min pool size":
case "minimum pool size":
return Keyword.MinimumPoolSize;
case "max pool size":
case "maximum pool size":
return Keyword.MaximumPoolSize;
case "connection lifetime":
case "load balance timeout":
return Keyword.ConnectionLifetime;
case "driver":
case "driver type": // added 02/02/07 Sean Wright
return Keyword.DriverType;
case "protocol":
case "connection protocol": // added 02/02/07 Sean Wright
return Keyword.Protocol;
case "allow zero datetime":
case "allowzerodatetime":
return Keyword.AllowZeroDatetime;
case "useperformancemonitor":
case "use performance monitor":
return Keyword.UsePerformanceMonitor;
case "procedure cache size":
case "procedurecachesize":
case "procedure cache":
case "procedurecache":
return Keyword.ProcedureCacheSize;
case "connection reset":
return Keyword.ConnectionReset;
case "ignore prepare":
return Keyword.IgnorePrepare;
case "encrypt":
return Keyword.UseSSL;
}
throw new ArgumentException(Resources.KeywordNotSupported, key);
}
private object GetValue(Keyword kw)
{
switch (kw)
{
case Keyword.UserID: return UserID;
case Keyword.Password: return Password;
case Keyword.Port: return Port;
case Keyword.Server: return Server;
case Keyword.UseUsageAdvisor: return UseUsageAdvisor;
case Keyword.CharacterSet: return CharacterSet;
case Keyword.Compress: return UseCompression;
case Keyword.PipeName: return PipeName;
case Keyword.Logging: return Logging;
case Keyword.OldSyntax: return UseOldSyntax;
case Keyword.SharedMemoryName: return SharedMemoryName;
case Keyword.AllowBatch: return AllowBatch;
case Keyword.ConvertZeroDatetime: return ConvertZeroDateTime;
case Keyword.PersistSecurityInfo: return PersistSecurityInfo;
case Keyword.Database: return Database;
case Keyword.ConnectionTimeout: return ConnectionTimeout;
case Keyword.Pooling: return Pooling;
case Keyword.MinimumPoolSize: return MinimumPoolSize;
case Keyword.MaximumPoolSize: return MaximumPoolSize;
case Keyword.ConnectionLifetime: return ConnectionLifeTime;
case Keyword.DriverType: return DriverType;
case Keyword.Protocol: return ConnectionProtocol;
case Keyword.ConnectionReset: return ConnectionReset;
case Keyword.ProcedureCacheSize: return ProcedureCacheSize;
case Keyword.AllowZeroDatetime: return AllowZeroDateTime;
case Keyword.UsePerformanceMonitor: return UsePerformanceMonitor;
case Keyword.IgnorePrepare: return IgnorePrepare;
case Keyword.UseSSL: return UseSSL;
default: return null; /* this will never happen */
}
}
private void SetValue(Keyword kw, object value)
{
switch (kw)
{
case Keyword.UserID: UserID = (string)value; break;
case Keyword.Password: Password = (string)value; break;
case Keyword.Port: Port = ConvertToUInt(value); break;
case Keyword.Server: Server = (string)value; break;
case Keyword.UseUsageAdvisor: UseUsageAdvisor = ConvertToBool(value); break;
case Keyword.CharacterSet: CharacterSet = (string)value; break;
case Keyword.Compress: UseCompression = ConvertToBool(value); break;
case Keyword.PipeName: PipeName = (string)value; break;
case Keyword.Logging: Logging = ConvertToBool(value); break;
case Keyword.OldSyntax: UseOldSyntax = ConvertToBool(value); break;
case Keyword.SharedMemoryName: SharedMemoryName = (string)value; break;
case Keyword.AllowBatch: AllowBatch = ConvertToBool(value); break;
case Keyword.ConvertZeroDatetime: ConvertZeroDateTime = ConvertToBool(value); break;
case Keyword.PersistSecurityInfo: PersistSecurityInfo = ConvertToBool(value); break;
case Keyword.Database: Database = (string)value; break;
case Keyword.ConnectionTimeout: ConnectionTimeout = ConvertToUInt(value); break;
case Keyword.Pooling: Pooling = ConvertToBool(value); break;
case Keyword.MinimumPoolSize: MinimumPoolSize = ConvertToUInt(value); break;
case Keyword.MaximumPoolSize: MaximumPoolSize = ConvertToUInt(value); break;
case Keyword.ConnectionLifetime: ConnectionLifeTime = ConvertToUInt(value); break;
case Keyword.DriverType: DriverType = (MySqlDriverType)value; break;
case Keyword.Protocol: ConnectionProtocol = (MySqlConnectionProtocol)value; break;
case Keyword.ConnectionReset: ConnectionReset = ConvertToBool(value); break;
case Keyword.UsePerformanceMonitor: UsePerformanceMonitor = ConvertToBool(value); break;
case Keyword.AllowZeroDatetime: AllowZeroDateTime = ConvertToBool(value); break;
case Keyword.ProcedureCacheSize: ProcedureCacheSize = ConvertToUInt(value); break;
case Keyword.IgnorePrepare: IgnorePrepare = ConvertToBool(value); break;
case Keyword.UseSSL: UseSSL = ConvertToBool(value); break;
}
}
///
/// Gets or sets the value associated with the specified key. In C#, this property
/// is the indexer.
///
/// The key of the item to get or set.
/// The value associated with the specified key.
public override object this[string key]
{
get
{
Keyword kw = GetKey(key);
return GetValue(kw);
}
set
{
Keyword kw = GetKey(key);
if (kw != Keyword.Password)
persistConnString.AppendFormat("{0}={1};", key, value);
SetValue(kw, value);
}
}
}
internal enum Keyword
{
UserID,
Password,
Server,
Port,
UseUsageAdvisor,
CharacterSet,
Compress,
PipeName,
Logging,
OldSyntax,
SharedMemoryName,
AllowBatch,
ConvertZeroDatetime,
PersistSecurityInfo,
Database,
ConnectionTimeout,
Pooling,
MinimumPoolSize,
MaximumPoolSize,
ConnectionLifetime,
DriverType,
Protocol,
ConnectionReset,
AllowZeroDatetime,
UsePerformanceMonitor,
ProcedureCacheSize,
IgnorePrepare,
UseSSL
}
}