Index: trunk/nhibernate/src/NHibernate.Test/DialectTest/FirebirdDialectFixture.cs =================================================================== --- trunk/nhibernate/src/NHibernate.Test/DialectTest/FirebirdDialectFixture.cs (revision 0) +++ trunk/nhibernate/src/NHibernate.Test/DialectTest/FirebirdDialectFixture.cs (revision 0) @@ -0,0 +1,25 @@ +using NHibernate.Dialect; +using NHibernate.SqlCommand; +using NUnit.Framework; + +namespace NHibernate.Test.DialectTest +{ + [TestFixture] + public class FirebirdDialectFixture + { + [Test] + public void GetLimitString() + { + FirebirdDialect d = new FirebirdDialect(); + + SqlString str = d.GetLimitString(new SqlString("SELECT * FROM fish"), 0, 10); + Assert.AreEqual("SELECT first 10 * FROM fish", str.ToString()); + + str = d.GetLimitString(new SqlString("SELECT * FROM fish ORDER BY name"), 5, 15); + Assert.AreEqual("SELECT first 15 skip 5 * FROM fish ORDER BY name", str.ToString()); + + str = d.GetLimitString(new SqlString("SELECT * FROM fish ORDER BY name DESC"), 7, 28); + Assert.AreEqual("SELECT first 28 skip 7 * FROM fish ORDER BY name DESC", str.ToString()); + } + } +} Index: trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj =================================================================== --- trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj (revision 2194) +++ trunk/nhibernate/src/NHibernate.Test/NHibernate.Test-2.0.csproj (working copy) @@ -75,6 +75,7 @@ + Index: trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs =================================================================== --- trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs (revision 2194) +++ trunk/nhibernate/src/NHibernate/Dialect/FirebirdDialect.cs (working copy) @@ -150,6 +150,69 @@ get { return true; } } + public override bool SupportsLimit + { + get { return true; } + } + + public override bool SupportsLimitOffset + { + get { return true; } + } + + /// + /// Add a FIRST x [SKIP] y clause to the given SQL SELECT + /// + /// A Query in the form of a SqlString. + /// Maximum number of rows to be returned by the query + /// Offset of the first row to process in the result set + /// A new SqlString that contains the FIRST clause. + public override SqlString GetLimitString(SqlString querySqlString, int offset, int limit) + { + /* + * "SELECT FIRST x [SKIP y] rest-of-sql-statement" + */ + querySqlString = querySqlString.Compact(); + SqlStringBuilder pagingBuilder = new SqlStringBuilder(); + bool firstAdded = false; + foreach (object sqlPart in querySqlString.SqlParts) + { + if (!firstAdded) + { + string sqlPartString = sqlPart as string; + if (sqlPartString != null) + { + string sqlFragment = sqlPartString.TrimStart(); + int insertIndex = GetAfterSelectInsertPoint(sqlFragment); + if (insertIndex > 0) + { + string newFragment = string.Empty; + + if (offset > 0) + { + newFragment = sqlFragment.Insert(insertIndex, " first " + limit.ToString() + " skip " + offset.ToString()); + } + else + { + newFragment = sqlFragment.Insert(insertIndex, " first " + limit.ToString()); + } + pagingBuilder.Add(newFragment); + firstAdded = true; + continue; + } + } + } + pagingBuilder.AddObject(sqlPart); + } + + return pagingBuilder.ToSqlString(); + } + + public override bool SupportsVariableLimit + { + get { return false; } + } + public override string ForUpdateString { get { return " with lock"; } @@ -164,5 +227,19 @@ { return " for update of " + aliases + " with lock"; } + + private static int GetAfterSelectInsertPoint(string fragment) + { + string fragmentLowerCased = fragment.ToLower(System.Globalization.CultureInfo.InvariantCulture); + if (fragmentLowerCased.StartsWith("select distinct")) + { + return 15; + } + else if (fragmentLowerCased.StartsWith("select")) + { + return 6; + } + return 0; + } } } \ No newline at end of file