context: using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Data;
  using System.Data.Common;
  using System.Text;
  using NHibernate.Dialect.Function;
  using NHibernate.Dialect.Lock;
  using NHibernate.Dialect.Schema;
  using NHibernate.Exceptions;
  using NHibernate.Id;
  using NHibernate.Mapping;
  using NHibernate.Persister.Entity;
  using NHibernate.SqlCommand;
  using NHibernate.SqlTypes;
  using NHibernate.Type;
  using NHibernate.Util;
  using Environment = NHibernate.Cfg.Environment;
  
  namespace NHibernate.Dialect
  {
  	/// <summary>
  	/// Represents a dialect of SQL implemented by a particular RDBMS. Subclasses
  	/// implement NHibernate compatibility with different systems.
  	/// </summary>
  	/// <remarks>
  	/// Subclasses should provide a public default constructor that <c>Register()</c>
  	/// a set of type mappings and default Hibernate properties.
  	/// </remarks>
  	public abstract class Dialect
  	{
  		private static readonly IInternalLogger Log = LoggerProvider.LoggerFor(typeof(Dialect));
  
  		protected const string DefaultBatchSize = "15";
  		protected const string NoBatch = "0";
  
  		/// <summary> Characters used for quoting sql identifiers </summary>
  		public const string PossibleQuoteChars = "`'\"[";
  
  		/// <summary> Characters used for closing quoted sql identifiers </summary>
  		public const string PossibleClosedQuoteChars = "`'\"]";
  		
  		private readonly TypeNames _typeNames = new TypeNames();
  		private readonly TypeNames _hibernateTypeNames = new TypeNames();
  		private readonly IDictionary<string, string> _properties = new Dictionary<string, string>();
  		private readonly IDictionary<string, ISQLFunction> _sqlFunctions;
  		private readonly HashSet<string> _sqlKeywords = new HashSet<string>();
  
  		private static readonly IDictionary<string, ISQLFunction> StandardAggregateFunctions = CollectionHelper.CreateCaseInsensitiveHashtable<ISQLFunction>();
  
  		private static readonly IViolatedConstraintNameExtracter Extracter;
  
  		#region Constructors and factory methods
  
  		static Dialect()
  		{
  			StandardAggregateFunctions["count"] = new CountQueryFunctionInfo();
  			StandardAggregateFunctions["avg"] = new AvgQueryFunctionInfo();
  			StandardAggregateFunctions["max"] = new ClassicAggregateFunction("max", false);
  			StandardAggregateFunctions["min"] = new ClassicAggregateFunction("min", false);
  			StandardAggregateFunctions["sum"] = new SumQueryFunctionInfo();
  
  			Extracter = new NoOpViolatedConstraintNameExtracter();
  		}
  
  		/// <summary>
  		/// The base constructor for Dialect.
  		/// </summary>
  		/// <remarks>
  		/// Every subclass should override this and call Register() with every <see cref="DbType"/> except
  		/// <see cref="DbType.Object"/>, <see cref="DbType.SByte"/>, <see cref="DbType.UInt16"/>, <see cref="DbType.UInt32"/>, 
  		/// <see cref="DbType.UInt64"/>, <see cref="DbType.VarNumeric"/>.
  		/// 
  		/// <para>
  		/// The Default properties for this Dialect should also be set - such as whether or not to use outer-joins
  		/// and what the batch size should be.
  		/// </para>
  		/// </remarks>
  		protected Dialect()
  		{
  			Log.Info("Using dialect: " + this);
  
  			_sqlFunctions = CollectionHelper.CreateCaseInsensitiveHashtable(StandardAggregateFunctions);
  			
  			// standard sql92 functions (can be overridden by subclasses)
  			RegisterFunction("substring", new AnsiSubstringFunction());
  			RegisterFunction("locate", new StandardSQLFunction("locate", NHibernateUtil.Int32));
  			RegisterFunction("trim", new AnsiTrimFunction());
  			RegisterFunction("length", new StandardSQLFunction("length", NHibernateUtil.Int32));
  			RegisterFunction("bit_length", new StandardSQLFunction("bit_length", NHibernateUtil.Int32));
  			RegisterFunction("coalesce", new StandardSQLFunction("coalesce"));
  			RegisterFunction("nullif", new StandardSQLFunction("nullif"));
  			RegisterFunction("abs", new StandardSQLFunction("abs"));
  			RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32));
  			RegisterFunction("sqrt", new StandardSQLFunction("sqrt", NHibernateUtil.Double));
  			RegisterFunction("upper", new StandardSQLFunction("upper"));
  			RegisterFunction("lower", new StandardSQLFunction("lower"));
  			RegisterFunction("cast", new CastFunction());
  			RegisterFunction("extract", new AnsiExtractFunction());
  			RegisterFunction("concat", new VarArgsSQLFunction(NHibernateUtil.String, "(", "||", ")"));
  
  			// the syntax of current_timestamp is extracted from H3.2 tests 
  			// - test\hql\ASTParserLoadingTest.java
  			// - test\org\hibernate\test\hql\HQLTest.java
  			RegisterFunction("current_timestamp", new NoArgSQLFunction("current_timestamp", NHibernateUtil.DateTime, true));
  			RegisterFunction("sysdate", new NoArgSQLFunction("sysdate", NHibernateUtil.DateTime, false));
  
  			//map second/minute/hour/day/month/year to ANSI extract(), override on subclasses
  			RegisterFunction("second", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(second from ?1)"));
  			RegisterFunction("minute", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(minute from ?1)"));
  			RegisterFunction("hour", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(hour from ?1)"));
  			RegisterFunction("day", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(day from ?1)"));
  			RegisterFunction("month", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(month from ?1)"));
  			RegisterFunction("year", new SQLFunctionTemplate(NHibernateUtil.Int32, "extract(year from ?1)"));
  
  			// Bitwise operations
  			RegisterFunction("band", new BitwiseNativeOperation("&"));
  			RegisterFunction("bor", new BitwiseNativeOperation("|"));
  			RegisterFunction("bxor", new BitwiseNativeOperation("^"));
  			RegisterFunction("bnot", new BitwiseNativeOperation("~", true));
  
  			RegisterFunction("str", new SQLFunctionTemplate(NHibernateUtil.String, "cast(?1 as char)"));
  
  			// register hibernate types for default use in scalar sqlquery type auto detection
  			RegisterHibernateType(DbType.Int64, NHibernateUtil.Int64.Name);
  			RegisterHibernateType(DbType.Binary, NHibernateUtil.Binary.Name);
  			RegisterHibernateType(DbType.Boolean, NHibernateUtil.Boolean.Name);
  			RegisterHibernateType(DbType.AnsiString, NHibernateUtil.Character.Name);
  			RegisterHibernateType(DbType.Date, NHibernateUtil.Date.Name);
  			RegisterHibernateType(DbType.Double, NHibernateUtil.Double.Name);
  			RegisterHibernateType(DbType.Single, NHibernateUtil.Single.Name);
  			RegisterHibernateType(DbType.Int32, NHibernateUtil.Int32.Name);
  			RegisterHibernateType(DbType.Int16, NHibernateUtil.Int16.Name);
  			RegisterHibernateType(DbType.SByte, NHibernateUtil.SByte.Name);
  			RegisterHibernateType(DbType.Time, NHibernateUtil.Time.Name);
  			RegisterHibernateType(DbType.DateTime, NHibernateUtil.Timestamp.Name);
  			RegisterHibernateType(DbType.String, NHibernateUtil.String.Name);
  			RegisterHibernateType(DbType.VarNumeric, NHibernateUtil.Decimal.Name);
  			RegisterHibernateType(DbType.Decimal, NHibernateUtil.Decimal.Name);
  		}
  
  		/// <summary> Get an instance of the dialect specified by the current <see cref="Cfg.Environment"/> properties. </summary>
  		/// <returns> The specified Dialect </returns>
  		public static Dialect GetDialect()
  		{
  			string dialectName;
  			try
  			{
  				dialectName = Environment.Properties[Environment.Dialect];
  			}
  			catch (Exception e)
  			{
  				throw new HibernateException("The dialect was not set. Set the property 'dialect'.", e);
  			}
  			return InstantiateDialect(dialectName);
  		}
  
  		/// <summary>
  		/// Get <see cref="Dialect"/> from a property bag (prop name <see cref="Cfg.Environment.Dialect"/>)
  		/// </summary>
  		/// <param name="props">The property bag.</param>
  		/// <returns>An instance of <see cref="Dialect"/>.</returns>
  		/// <exception cref="System.ArgumentNullException">When <paramref name="props"/> is null.</exception>
  		/// <exception cref="HibernateException">When the property bag don't contains de property <see cref="Cfg.Environment.Dialect"/>.</exception>
  		public static Dialect GetDialect(IDictionary<string, string> props)
  		{
  			if (props == null)
  				throw new ArgumentNullException("props");
  			string dialectName;
  			if (props.TryGetValue(Environment.Dialect, out dialectName) == false)
  				throw new InvalidOperationException("Could not find the dialect in the configuration");
  			if (dialectName == null)
  			{
  				return GetDialect();
  			}
  
  			return InstantiateDialect(dialectName);
  		}
  
  		private static Dialect InstantiateDialect(string dialectName)
  		{
  			try
  			{
  				return (Dialect)Environment.BytecodeProvider.ObjectsFactory.CreateInstance(ReflectHelper.ClassForName(dialectName));
  			}
  			catch (Exception e)
  			{
  				throw new HibernateException("Could not instantiate dialect class " + dialectName, e);
  			}
  		}
  
  		#endregion
  
  		#region Database type mapping support
  
  		/// <summary>
  		/// Get the name of the database type associated with the given 
  		/// <see cref="SqlTypes.SqlType"/>,
  		/// </summary>
  		/// <param name="sqlType">The SqlType</param>
  		/// <returns>The database type name used by ddl.</returns>
  		public virtual string GetTypeName(SqlType sqlType)
  		{
  			if (sqlType.LengthDefined || sqlType.PrecisionDefined)
  			{
  				string resultWithLength = _typeNames.Get(sqlType.DbType, sqlType.Length, sqlType.Precision, sqlType.Scale);
  				if (resultWithLength != null) return resultWithLength;
  			}
  
  			string result = _typeNames.Get(sqlType.DbType);
  			if (result == null)
  			{
  				throw new HibernateException(string.Format("No default type mapping for SqlType {0}", sqlType));
  			}
  
  			return result;
  		}
  
  		/// <summary>
  		/// Get the name of the database type associated with the given
  		/// <see cref="SqlType"/>.
  		/// </summary>
  		/// <param name="sqlType">The SqlType </param>
  		/// <param name="length">The datatype length </param>
  		/// <param name="precision">The datatype precision </param>
  		/// <param name="scale">The datatype scale </param>
  		/// <returns>The database type name used by ddl.</returns>
  		public virtual string GetTypeName(SqlType sqlType, int length, int precision, int scale)
  		{
  			string result = _typeNames.Get(sqlType.DbType, length, precision, scale);
  			if (result == null)
  			{
  				throw new HibernateException(string.Format("No type mapping for SqlType {0} of length {1}", sqlType, length));
  			}
  			return result;
  		}
  
  		/// <summary>
  		/// Gets the name of the longest registered type for a particular DbType.
  		/// </summary>
  		/// <param name="dbType"></param>
  		/// <returns></returns>
  		public virtual string GetLongestTypeName(DbType dbType)
  		{
  			return _typeNames.GetLongest(dbType);
  		}
  
  		/// <summary> 
  		/// Get the name of the database type appropriate for casting operations
  		/// (via the CAST() SQL function) for the given <see cref="SqlType"/> typecode.
  		/// </summary>
  		/// <param name="sqlType">The <see cref="SqlType"/> typecode </param>
  		/// <returns> The database type name </returns>
  		public virtual string GetCastTypeName(SqlType sqlType)
  		{
  			return GetTypeName(sqlType, Column.DefaultLength, Column.DefaultPrecision, Column.DefaultScale);
  		}
  
  		/// <summary>
  		/// Subclasses register a typename for the given type code and maximum
  		/// column length. <c>$l</c> in the type name will be replaced by the column
  		/// length (if appropriate)
  		/// </summary>
  		/// <param name="code">The typecode</param>
  		/// <param name="capacity">Maximum length of database type</param>
  		/// <param name="name">The database type name</param>
  		protected void RegisterColumnType(DbType code, int capacity, string name)
  		{
  			_typeNames.Put(code, capacity, name);
  		}
  
  		/// <summary>
  		/// Subclasses register a typename for the given type code. <c>$l</c> in the 
  		/// typename will be replaced by the column length (if appropriate).
  		/// </summary>
  		/// <param name="code">The typecode</param>
  		/// <param name="name">The database type name</param>
  		protected void RegisterColumnType(DbType code, string name)
  		{
  			_typeNames.Put(code, name);
  		}
  
  		#endregion
  
  		#region DDL support
  
  		/// <summary>
  		/// Do we need to drop constraints before dropping tables in the dialect?
  		/// </summary>
  		public virtual bool DropConstraints
  		{
  			get { return true; }
  		}
  
  		/// <summary>
  		/// Do we need to qualify index names with the schema name?
  		/// </summary>
  		public virtual bool QualifyIndexName
  		{
  			get { return true; }
  		}
  
  		/// <summary>
  		/// Does this dialect support the <c>UNIQUE</c> column syntax?
  		/// </summary>
  		public virtual bool SupportsUnique
  		{
  			get { return true; }
  		}
  
  		/// <summary> Does this dialect support adding Unique constraints via create and alter table ?</summary>
  		public virtual bool SupportsUniqueConstraintInCreateAlterTable
  		{
  			get { return true; }
  		}
  
  		/// <summary>
  		/// Does this dialect support adding foreign key constraints via alter table?  If not, it's assumed they can only be added through create table.
  		/// </summary>
  		public virtual bool SupportsForeignKeyConstraintInAlterTable
  		{
  			get { return true; }
  		}
  
  		/// <summary> 
  		/// The syntax used to add a foreign key constraint to a table.  If SupportsForeignKeyConstraintInAlterTable is false, the returned string will be added to the create table statement instead.  In this case, extra strings, like "add", that apply when using alter table should be omitted.
  		/// </summary>
  		/// <param name="constraintName">The FK constraint name. </param>
  		/// <param name="foreignKey">The names of the columns comprising the FK </param>
  		/// <param name="referencedTable">The table referenced by the FK </param>
  		/// <param name="primaryKey">The explicit columns in the referencedTable referenced by this FK. </param>
  		/// <param name="referencesPrimaryKey">
  		/// if false, constraint should be explicit about which column names the constraint refers to 
  		/// </param>
  		/// <returns> the "add FK" fragment </returns>
  		public virtual string GetAddForeignKeyConstraintString(string constraintName, string[] foreignKey, string referencedTable, string[] primaryKey, bool referencesPrimaryKey)
  		{
  			var res = new StringBuilder(200);
  
  			if (SupportsForeignKeyConstraintInAlterTable)
  				res.Append(" add");
  
  			res.Append(" constraint ")
  				.Append(constraintName)
  
gt: 				.Append(" foreign key (")