Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MySQL, USE INDEX on TABLE and JOIN. #695

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
35 changes: 35 additions & 0 deletions QueryBuilder.Tests/Firebird/FirebirdJoinTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.Firebird
{
public class FirebirdJoinTests : TestSupport
{
private readonly FirebirdCompiler compiler;

public FirebirdJoinTests()
{
compiler = Compilers.Get<FirebirdCompiler>(EngineCodes.Firebird);
}

[Fact]
public void Join()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TABLEA\" ON \"COLUMN1\" = \"COLUMNA\"", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TABLEA\" ON \"COLUMN1\" = \"COLUMNA\"", compiler.CompileJoins(ctx));
}
}
}
53 changes: 53 additions & 0 deletions QueryBuilder.Tests/MySql/MySqlIndexHintTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.MySql
{
public class MySqlIndexHintTests : TestSupport
{
private readonly MySqlCompiler compiler;

public MySqlIndexHintTests()
{
compiler = Compilers.Get<MySqlCompiler>(EngineCodes.MySql);
}

[Fact]
public void WithNoIndexHint()
{
var query = new Query("Table");
var ctx = new SqlResult { Query = query };

Assert.Equal("FROM `Table`", compiler.CompileFrom(ctx));
}

[Fact]
public void WithIndexHint()
{
var query = new Query("Table", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("FROM `Table` USE INDEX(index1)", compiler.CompileFrom(ctx));
}

[Fact]
public void JoinWithNoIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN `TableA` ON `Column1` = `ColumnA`", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN `TableA` USE INDEX(index1) ON `Column1` = `ColumnA`", compiler.CompileJoins(ctx));
}
}
}
35 changes: 35 additions & 0 deletions QueryBuilder.Tests/Oracle/OracleJoinTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.Oracle
{
public class OracleJoinTests : TestSupport
{
private readonly OracleCompiler compiler;

public OracleJoinTests()
{
compiler = Compilers.Get<OracleCompiler>(EngineCodes.Oracle);
}

[Fact]
public void Join()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}
}
}
35 changes: 35 additions & 0 deletions QueryBuilder.Tests/PostgreSql/PostgreServerJoinTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.PostgreSql
{
public class PostgreServerJoinTests : TestSupport
{
private readonly PostgresCompiler compiler;

public PostgreServerJoinTests()
{
compiler = Compilers.Get<PostgresCompiler>(EngineCodes.PostgreSql);
}

[Fact]
public void Join()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}
}
}
35 changes: 35 additions & 0 deletions QueryBuilder.Tests/SqlServer/SqlServerJoinTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.SqlServer
{
public class SqlServerJoinTests : TestSupport
{
private readonly SqlServerCompiler compiler;

public SqlServerJoinTests()
{
compiler = Compilers.Get<SqlServerCompiler>(EngineCodes.SqlServer);
}

[Fact]
public void Join()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN [TableA] ON [Column1] = [ColumnA]", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN [TableA] ON [Column1] = [ColumnA]", compiler.CompileJoins(ctx));
}
}
}
35 changes: 35 additions & 0 deletions QueryBuilder.Tests/Sqlite/SqlliteJoinTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
using SqlKata.Compilers;
using SqlKata.Tests.Infrastructure;
using Xunit;

namespace SqlKata.Tests.Sqlite
{
public class SqlliteJoinTests : TestSupport
{
private readonly SqliteCompiler compiler;

public SqlliteJoinTests()
{
compiler = Compilers.Get<SqliteCompiler>(EngineCodes.Sqlite);
}

[Fact]
public void Join()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}


[Fact]
public void JoinWithIndexHint()
{
var query = new Query("Table").Join("TableA", "Column1", "ColumnA", indexHint: "index1");
var ctx = new SqlResult { Query = query };

Assert.Equal("\nINNER JOIN \"TableA\" ON \"Column1\" = \"ColumnA\"", compiler.CompileJoins(ctx));
}
}
}
16 changes: 15 additions & 1 deletion QueryBuilder/BaseQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,16 @@ public Q From(string table)
});
}

public Q From(Query query, string alias = null)
public Q From(string table, string indexHint)
{
return AddOrReplaceComponent("from", new FromClause
{
Table = table,
IndexHint = indexHint
});
}

public Q From(Query query, string alias = null, string indexHint = null)
{
query = query.Clone();
query.SetParent((Q)this);
Expand All @@ -282,6 +291,11 @@ public Q From(Query query, string alias = null)
query.As(alias);
};

if (indexHint != null)
{
query.UseIndexHint(alias);
};

return AddOrReplaceComponent("from", new QueryFromClause
{
Query = query
Expand Down
6 changes: 5 additions & 1 deletion QueryBuilder/Clauses/FromClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ namespace SqlKata
public abstract class AbstractFrom : AbstractClause
{
protected string _alias;
protected string _indexHint { get; set; }

/// <summary>
/// Try to extract the Alias for the current clause.
/// </summary>
/// <returns></returns>
public virtual string Alias { get => _alias; set => _alias = value; }

public string IndexHint { get => _indexHint; set => _indexHint = value; }
}

/// <summary>
Expand Down Expand Up @@ -71,6 +74,7 @@ public override AbstractClause Clone()
{
Engine = Engine,
Alias = Alias,
IndexHint = IndexHint,
Query = Query.Clone(),
Component = Component,
};
Expand Down Expand Up @@ -116,4 +120,4 @@ public override AbstractClause Clone()
};
}
}
}
}
2 changes: 2 additions & 0 deletions QueryBuilder/Clauses/JoinClause.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public override AbstractClause Clone()
public class DeepJoin : AbstractJoin
{
public string Type { get; set; }
public string IndexHint { get; set; }
public string Expression { get; set; }
public string SourceKeySuffix { get; set; }
public string TargetKey { get; set; }
Expand All @@ -39,6 +40,7 @@ public override AbstractClause Clone()
Engine = Engine,
Component = Component,
Type = Type,
IndexHint = IndexHint,
Expression = Expression,
SourceKeySuffix = SourceKeySuffix,
TargetKey = TargetKey,
Expand Down
2 changes: 1 addition & 1 deletion QueryBuilder/Compilers/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -897,7 +897,7 @@ public virtual string CompileFalse()
return "false";
}

private InvalidCastException InvalidClauseException(string section, AbstractClause clause)
protected InvalidCastException InvalidClauseException(string section, AbstractClause clause)
{
return new InvalidCastException($"Invalid type \"{clause.GetType().Name}\" provided for the \"{section}\" clause.");
}
Expand Down
63 changes: 63 additions & 0 deletions QueryBuilder/Compilers/MySqlCompiler.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using System.Linq;

namespace SqlKata.Compilers
{
public class MySqlCompiler : Compiler
Expand All @@ -10,6 +12,67 @@ public MySqlCompiler()

public override string EngineCode { get; } = EngineCodes.MySql;

public override string CompileTableExpression(SqlResult ctx, AbstractFrom from)
{
if (from is RawFromClause raw)
{
ctx.Bindings.AddRange(raw.Bindings);
return WrapIdentifiers(raw.Expression);
}

if (from is QueryFromClause queryFromClause)
{
var fromQuery = queryFromClause.Query;

var alias = string.IsNullOrEmpty(fromQuery.QueryAlias) ? "" : $" {TableAsKeyword}" + WrapValue(fromQuery.QueryAlias);

var subCtx = CompileSelectQuery(fromQuery);

ctx.Bindings.AddRange(subCtx.Bindings);

if (!string.IsNullOrWhiteSpace(fromQuery.IndexHint))
{
subCtx.RawSql += $" USE INDEX({fromQuery.IndexHint})";
}

return "(" + subCtx.RawSql + ")" + alias;
}

if (from is FromClause fromClause)
{
var fromStatment = Wrap(fromClause.Table);

if (!string.IsNullOrWhiteSpace(fromClause.IndexHint))
{
fromStatment += $" USE INDEX({fromClause.IndexHint})";
}

return fromStatment;
}

throw InvalidClauseException("TableExpression", from);
}

public override string CompileJoin(SqlResult ctx, Join join, bool isNested = false)
{
var from = join.GetOneComponent<AbstractFrom>("from", EngineCode);
var conditions = join.GetComponents<AbstractCondition>("where", EngineCode);

var joinTable = CompileTableExpression(ctx, from);
var constraints = CompileConditions(ctx, conditions);

var onClause = conditions.Any() ? $" ON {constraints}" : "";

var indexHint = "";

if (!string.IsNullOrWhiteSpace(join.IndexHint))
{
indexHint = $" USE INDEX({join.IndexHint})";
}

return $"{join.Type} {joinTable}{indexHint}{onClause}";
}

public override string CompileLimit(SqlResult ctx)
{
var limit = ctx.Query.GetLimit(EngineCode);
Expand Down