using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using NHibernate.Dialect.Function;
using NHibernate.Dialect.Schema;
using NHibernate.Engine;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Type;
using NHibernate.Util;
using Environment = NHibernate.Cfg.Environment;
namespace NHibernate.Dialect
{
///
/// A dialect for Oracle 8i.
///
public class Oracle8iDialect : Dialect
{
public override string CurrentTimestampSelectString
{
get { return "select sysdate from dual"; }
}
public override string CurrentTimestampSQLFunctionName
{
get { return "sysdate"; }
}
public override string AddColumnString
{
get { return "add"; }
}
public override string CascadeConstraintsString
{
get { return " cascade constraints"; }
}
public override string QuerySequencesString
{
get { return "select sequence_name from user_sequences"; }
}
public override string SelectGUIDString
{
get { return "select rawtohex(sys_guid()) from dual"; }
}
public override string CreateTemporaryTableString
{
get { return "create global temporary table"; }
}
public override string CreateTemporaryTablePostfix
{
get { return "on commit delete rows"; }
}
public override bool IsCurrentTimestampSelectStringCallable
{
get { return false; }
}
public Oracle8iDialect()
{
RegisterCharacterTypeMappings();
RegisterNumericTypeMappings();
RegisterDateTimeTypeMappings();
RegisterLargeObjectTypeMappings();
RegisterGuidTypeMapping();
RegisterReverseHibernateTypeMappings();
RegisterFunctions();
RegisterDefaultProperties();
}
protected virtual void RegisterGuidTypeMapping()
{
RegisterColumnType(DbType.Guid, "RAW(16)");
}
protected virtual void RegisterCharacterTypeMappings()
{
RegisterColumnType(DbType.AnsiStringFixedLength, "CHAR(255)");
RegisterColumnType(DbType.AnsiStringFixedLength, 2000, "CHAR($l)");
RegisterColumnType(DbType.AnsiString, "VARCHAR2(255)");
RegisterColumnType(DbType.AnsiString, 4000, "VARCHAR2($l)");
RegisterColumnType(DbType.StringFixedLength, "NCHAR(255)");
RegisterColumnType(DbType.StringFixedLength, 2000, "NCHAR($l)");
RegisterColumnType(DbType.String, "NVARCHAR2(255)");
RegisterColumnType(DbType.String, 4000, "NVARCHAR2($l)");
}
protected virtual void RegisterNumericTypeMappings()
{
RegisterColumnType(DbType.Boolean, "NUMBER(1,0)");
RegisterColumnType(DbType.Byte, "NUMBER(3,0)");
RegisterColumnType(DbType.Int16, "NUMBER(5,0)");
RegisterColumnType(DbType.Int32, "NUMBER(10,0)");
RegisterColumnType(DbType.Int64, "NUMBER(20,0)");
RegisterColumnType(DbType.UInt16, "NUMBER(5,0)");
RegisterColumnType(DbType.UInt32, "NUMBER(10,0)");
RegisterColumnType(DbType.UInt64, "NUMBER(20,0)");
RegisterColumnType(DbType.Currency, "NUMBER(20,2)");
RegisterColumnType(DbType.Currency, "NUMBER($p,$s)");
RegisterColumnType(DbType.Single, "FLOAT(24)");
RegisterColumnType(DbType.Double, "DOUBLE PRECISION");
RegisterColumnType(DbType.Double, 19, "NUMBER($p,$s)");
RegisterColumnType(DbType.Decimal, "NUMBER(19,5)");
RegisterColumnType(DbType.Decimal, 19, "NUMBER($p,$s)");
}
protected virtual void RegisterDateTimeTypeMappings()
{
RegisterColumnType(DbType.Date, "DATE");
RegisterColumnType(DbType.DateTime, "DATE");
RegisterColumnType(DbType.Time, "DATE");
}
protected virtual void RegisterLargeObjectTypeMappings()
{
RegisterColumnType(DbType.Binary, "RAW(2000)");
RegisterColumnType(DbType.Binary, 2000, "RAW($l)");
RegisterColumnType(DbType.Binary, 2147483647, "BLOB");
RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB"); // should use the IType.ClobType
RegisterColumnType(DbType.String, 1073741823, "NCLOB");
}
protected virtual void RegisterReverseHibernateTypeMappings() {}
protected virtual void RegisterFunctions()
{
RegisterFunction("abs", new StandardSQLFunction("abs"));
RegisterFunction("sign", new StandardSQLFunction("sign", NHibernateUtil.Int32));
RegisterFunction("acos", new StandardSQLFunction("acos", NHibernateUtil.Double));
RegisterFunction("asin", new StandardSQLFunction("asin", NHibernateUtil.Double));
RegisterFunction("atan", new StandardSQLFunction("atan", NHibernateUtil.Double));
RegisterFunction("cos", new StandardSQLFunction("cos", NHibernateUtil.Double));
RegisterFunction("cosh", new StandardSQLFunction("cosh", NHibernateUtil.Double));
RegisterFunction("exp", new StandardSQLFunction("exp", NHibernateUtil.Double));
RegisterFunction("ln", new StandardSQLFunction("ln", NHibernateUtil.Double));
RegisterFunction("sin", new StandardSQLFunction("sin", NHibernateUtil.Double));
RegisterFunction("sinh", new StandardSQLFunction("sinh", NHibernateUtil.Double));
RegisterFunction("stddev", new StandardSQLFunction("stddev", NHibernateUtil.Double));
RegisterFunction("sqrt", new StandardSQLFunction("sqrt", NHibernateUtil.Double));
RegisterFunction("tan", new StandardSQLFunction("tan", NHibernateUtil.Double));
RegisterFunction("tanh", new StandardSQLFunction("tanh", NHibernateUtil.Double));
RegisterFunction("variance", new StandardSQLFunction("variance", NHibernateUtil.Double));
RegisterFunction("round", new StandardSQLFunction("round"));
RegisterFunction("trunc", new StandardSQLFunction("trunc"));
RegisterFunction("ceil", new StandardSQLFunction("ceil"));
RegisterFunction("floor", new StandardSQLFunction("floor"));
RegisterFunction("chr", new StandardSQLFunction("chr", NHibernateUtil.Character));
RegisterFunction("initcap", new StandardSQLFunction("initcap"));
RegisterFunction("lower", new StandardSQLFunction("lower"));
RegisterFunction("ltrim", new StandardSQLFunction("ltrim"));
RegisterFunction("rtrim", new StandardSQLFunction("rtrim"));
RegisterFunction("soundex", new StandardSQLFunction("soundex"));
RegisterFunction("upper", new StandardSQLFunction("upper"));
RegisterFunction("ascii", new StandardSQLFunction("ascii", NHibernateUtil.Int32));
RegisterFunction("length", new StandardSQLFunction("length", NHibernateUtil.Int64));
RegisterFunction("left", new SQLFunctionTemplate(NHibernateUtil.String, "substr(?1, 1, ?2)"));
RegisterFunction("right", new SQLFunctionTemplate(NHibernateUtil.String, "substr(?1, -?2)"));
RegisterFunction("to_char", new StandardSQLFunction("to_char", NHibernateUtil.String));
RegisterFunction("to_date", new StandardSQLFunction("to_date", NHibernateUtil.Timestamp));
RegisterFunction("current_date", new NoArgSQLFunction("current_date", NHibernateUtil.Date, false));
RegisterFunction("current_time", new NoArgSQLFunction("current_timestamp", NHibernateUtil.Time, false));
RegisterFunction("current_timestamp", new CurrentTimeStamp());
RegisterFunction("last_day", new StandardSQLFunction("last_day", NHibernateUtil.Date));
RegisterFunction("sysdate", new NoArgSQLFunction("sysdate", NHibernateUtil.Date, false));
RegisterFunction("systimestamp", new NoArgSQLFunction("systimestamp", NHibernateUtil.Timestamp, false));
RegisterFunction("uid", new NoArgSQLFunction("uid", NHibernateUtil.Int32, false));
RegisterFunction("user", new NoArgSQLFunction("user", NHibernateUtil.String, false));
RegisterFunction("rowid", new NoArgSQLFunction("rowid", NHibernateUtil.Int64, false));
RegisterFunction("rownum", new NoArgSQLFunction("rownum", NHibernateUtil.Int64, false));
// Multi-param string dialect functions...
RegisterFunction("instr", new StandardSQLFunction("instr", NHibernateUtil.Int32));
RegisterFunction("instrb", new StandardSQLFunction("instrb", NHibernateUtil.Int32));
RegisterFunction("lpad", new StandardSQLFunction("lpad", NHibernateUtil.String));
RegisterFunction("replace", new StandardSQLFunction("replace", NHibernateUtil.String));
RegisterFunction("rpad", new StandardSQLFunction("rpad", NHibernateUtil.String));
RegisterFunction("substr", new StandardSQLFunction("substr", NHibernateUtil.String));
RegisterFunction("substrb", new StandardSQLFunction("substrb", NHibernateUtil.String));
RegisterFunction("translate", new StandardSQLFunction("translate", NHibernateUtil.String));
RegisterFunction("locate", new LocateFunction());
RegisterFunction("substring", new StandardSQLFunction("substr", NHibernateUtil.String));
RegisterFunction("locate", new SQLFunctionTemplate(NHibernateUtil.Int32, "instr(?2,?1)"));
RegisterFunction("bit_length", new SQLFunctionTemplate(NHibernateUtil.Int32, "vsize(?1)*8"));
RegisterFunction("coalesce", new NvlFunction());
// Multi-param numeric dialect functions...
RegisterFunction("atan2", new StandardSQLFunction("atan2", NHibernateUtil.Single));
RegisterFunction("log", new StandardSQLFunction("log", NHibernateUtil.Int32));
RegisterFunction("mod", new StandardSQLFunction("mod", NHibernateUtil.Int32));
RegisterFunction("nvl", new StandardSQLFunction("nvl"));
RegisterFunction("nvl2", new StandardSQLFunction("nvl2"));
RegisterFunction("power", new StandardSQLFunction("power", NHibernateUtil.Single));
// Multi-param date dialect functions...
RegisterFunction("add_months", new StandardSQLFunction("add_months", NHibernateUtil.Date));
RegisterFunction("months_between", new StandardSQLFunction("months_between", NHibernateUtil.Single));
RegisterFunction("next_day", new StandardSQLFunction("next_day", NHibernateUtil.Date));
RegisterFunction("str", new StandardSQLFunction("to_char", NHibernateUtil.String));
}
protected internal virtual void RegisterDefaultProperties()
{
//DefaultProperties[Environment.DefaultBatchFetchSize] = DefaultBatchSize; It can break some test and it is a user matter
// Oracle driver reports to support GetGeneratedKeys(), but they only
// support the version taking an array of the names of the columns to
// be returned (via its RETURNING clause). No other driver seems to
// support this overloaded version.
DefaultProperties[Environment.UseGetGeneratedKeys] = "false";
}
// features which change between 8i, 9i, and 10g ~~~~~~~~~~~~~~~~~~~~~~~~~~
///
/// Support for the oracle proprietary join syntax...
///
/// The orqacle join fragment
public override JoinFragment CreateOuterJoinFragment()
{
return new OracleJoinFragment();
}
///
/// Map case support to the Oracle DECODE function. Oracle did not
/// add support for CASE until 9i.
///
/// The oracle CASE -> DECODE fragment
public override CaseFragment CreateCaseFragment()
{
return new DecodeCaseFragment(this);
}
public override SqlString GetLimitString(SqlString sql, SqlString offset, SqlString limit)
{
sql = sql.Trim();
bool isForUpdate = false;
if (sql.EndsWithCaseInsensitive(" for update"))
{
sql = sql.Substring(0, sql.Length - 11);
isForUpdate = true;
}
string selectColumns = ExtractColumnOrAliasNames(sql);
var pagingSelect = new SqlStringBuilder(sql.Parts.Count + 10);
pagingSelect.Add("select " + selectColumns + " from ( select row_.*, rownum rownum_ from ( ");
pagingSelect.Add(sql);
if (offset != null && limit != null)
{
pagingSelect.Add(" ) row_ ) where rownum_ =>").Add(offset).Add(" and rownum_ < ").Add(offset).Add(" + ").Add(limit);
}
else if (limit != null)
{
pagingSelect.Add(" ) row_ ) where rownum_ <=").Add(limit);
}
else
{
// offset is specified, but limit is not.
pagingSelect.Add(" ) row_ ) where rownum_ =>").Add(offset);
}
if (isForUpdate)
{
pagingSelect.Add(" for update");
}
return pagingSelect.ToSqlString();
}
private string ExtractColumnOrAliasNames(SqlString select)
{
List columnsOrAliases;
Dictionary aliasToColumn;
ExtractColumnOrAliasNames(select, out columnsOrAliases, out aliasToColumn);
return StringHelper.Join(",", columnsOrAliases);
}
///
/// Allows access to the basic
/// implementation...
///
/// The mapping type
/// The appropriate select cluse fragment
public virtual string GetBasicSelectClauseNullString(SqlType sqlType)
{
return base.GetSelectClauseNullString(sqlType);
}
public override string GetSelectClauseNullString(SqlType sqlType)
{
switch (sqlType.DbType)
{
case DbType.String:
case DbType.AnsiString:
case DbType.StringFixedLength:
case DbType.AnsiStringFixedLength:
return "to_char(null)";
case DbType.Date:
case DbType.DateTime:
case DbType.Time:
return "to_date(null)";
default:
return "to_number(null)";
}
}
public override string GetSequenceNextValString(string sequenceName)
{
return "select " + GetSelectSequenceNextValString(sequenceName) + " from dual";
}
public override string GetSelectSequenceNextValString(string sequenceName)
{
return sequenceName + ".nextval";
}
public override SqlString AddIdentifierOutParameterToInsert(SqlString insertString, string identifierColumnName, string parameterName)
{
return insertString.Append(" returning " + identifierColumnName + " into :" + parameterName);
}
public override string GetCreateSequenceString(string sequenceName)
{
return "create sequence " + sequenceName; //starts with 1, implicitly
}
public override string GetDropSequenceString(string sequenceName)
{
return "drop sequence " + sequenceName;
}
public override bool DropConstraints
{
get { return false; }
}
public override string ForUpdateNowaitString
{
get { return " for update nowait"; }
}
public override bool SupportsSequences
{
get { return true; }
}
public override bool SupportsPooledSequences
{
get { return true; }
}
public override bool SupportsLimit
{
get { return true; }
}
public override string GetForUpdateString(string aliases)
{
return ForUpdateString + " of " + aliases;
}
public override string GetForUpdateNowaitString(string aliases)
{
return ForUpdateString + " of " + aliases + " nowait";
}
public override bool UseMaxForLimit
{
get { return true; }
}
public override bool ForUpdateOfColumns
{
get { return true; }
}
public override bool SupportsUnionAll
{
get { return true; }
}
public override bool SupportsCommentOn
{
get { return true; }
}
public override bool SupportsTemporaryTables
{
get { return true; }
}
public override string GenerateTemporaryTableName(String baseTableName)
{
string name = base.GenerateTemporaryTableName(baseTableName);
return name.Length > 30 ? name.Substring(1, (30) - (1)) : name;
}
public override bool DropTemporaryTableAfterUse()
{
return false;
}
public override bool SupportsCurrentTimestampSelection
{
get { return true; }
}
public override IDataBaseSchema GetDataBaseSchema(DbConnection connection)
{
return new OracleDataBaseSchema(connection);
}
#region Overridden informational metadata
public override bool SupportsEmptyInList
{
get { return false; }
}
public override bool SupportsExistsInSelect
{
get { return false; }
}
#endregion
#region Functions
[Serializable]
private class CurrentTimeStamp : NoArgSQLFunction
{
public CurrentTimeStamp() : base("current_timestamp", NHibernateUtil.DateTime, true) {}
public override SqlString Render(IList args, ISessionFactoryImplementor factory)
{
return new SqlString(Name);
}
}
[Serializable]
private class LocateFunction : ISQLFunction
{
private static readonly ISQLFunction LocateWith2Params = new SQLFunctionTemplate(NHibernateUtil.Int32,
"instr(?2, ?1)");
private static readonly ISQLFunction LocateWith3Params = new SQLFunctionTemplate(NHibernateUtil.Int32,
"instr(?2, ?1, ?3)");
#region Implementation of ISQLFunction
public IType ReturnType(IType columnType, IMapping mapping)
{
return NHibernateUtil.Int32;
}
public bool HasArguments
{
get { return true; }
}
public bool HasParenthesesIfNoArguments
{
get { return true; }
}
public SqlString Render(IList args, ISessionFactoryImplementor factory)
{
if (args.Count != 2 && args.Count != 3)
{
throw new QueryException("'locate' function takes 2 or 3 arguments");
}
if (args.Count == 2)
{
return LocateWith2Params.Render(args, factory);
}
else
{
return LocateWith3Params.Render(args, factory);
}
}
#endregion
}
#endregion
}
}