Skip to content

Commit

Permalink
Added support for oracle database
Browse files Browse the repository at this point in the history
  • Loading branch information
ElectricVampire committed Sep 15, 2024
1 parent 9c44314 commit 39f1088
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 2 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ View Entity Framework Core query plan directly inside Visual Studio.

## Introduction

With Entity Framework Core query plan debugger visualizer, you can view the query plan of your queries directly inside Visual Studio. Currently, the visualizer supports SQL Server and PostgreSQL.
With Entity Framework Core query plan debugger visualizer, you can view the query plan of your queries directly inside Visual Studio. Currently, the visualizer supports SQL Server, PostgreSQL and Oracle.

> [!IMPORTANT]
> The visualizer requires **Visual Studio Version 17.9.0 ([Released on February 13th](https://devblogs.microsoft.com/visualstudio/visual-studio-2022-17-9-now-available/)) or newer** and supports **EF Core 7 or newer**.
Expand All @@ -36,6 +36,10 @@ Click on 'Query Plan Visualizer' and the query plan will be displayed for your q

![PostgreSQL Plan](doc/PostgreSQLPlan1.png)

### Oracle:

![Oracle Plan](doc/OraclePlan.png)

## Known Issues:

- If query plan extraction takes more than 5 seconds, you will get [Evaluation timed out error](https://github.com/Giorgi/EFCore.Visualizer/issues/25)
Expand Down
Binary file added doc/OraclePlan.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/EFCore.Visualizer/EFCore.Visualizer.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<None Remove="Fonts\fa-solid-900.ttf" />
<None Remove="QueryPlanUserControl.xaml" />
<None Remove="Resources\Postgres\template.html" />
<None Remove="Resources\Oracle\template.html" />
</ItemGroup>

<ItemGroup>
Expand Down Expand Up @@ -54,6 +55,9 @@
<Content Include="Resources\SqlServer\*.*">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
<Content Include="Resources\Oracle\*.*">
<IncludeInVSIX>true</IncludeInVSIX>
</Content>
</ItemGroup>

<ItemGroup>
Expand Down
95 changes: 95 additions & 0 deletions src/EFCore.Visualizer/Resources/Oracle/template.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Query and Execution Plan</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
overflow-x: hidden;
}

.container {
width: 100%;
max-width: 100%;
margin: 0 auto;
background: #fff;
padding: 5px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}

.query, .plan {
margin-bottom: 5px;
}

.query {
margin: 0;
padding: 0;
}

pre {
white-space: pre;
background: #f0f0f0;
border: 1px solid #ddd;
padding: 10px;
border-radius: 4px;
overflow-x: auto;
font-size: 13px;
max-width: 100%;
word-wrap: normal;
}

.line {
border-top: 2px solid #000;
margin: 2px 0;
}
</style>
</head>
<body>

<div class="container">
<div class="query">
<pre id="query"></pre>
</div>

<div class="line"></div>

<div class="plan">
<pre id="plan"></pre>
</div>
</div>

<script>
function escapeHtml(text) {
return text
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}

function replaceNewlines(text) {
return text.replace(/\r\n|\r|\n/g, '<br>');
}

const query = '{query}';
const plan = `{plan}`;

document.getElementById('query').innerHTML = escapeHtml(query);
document.getElementById('plan').innerHTML = replaceNewlines(escapeHtml(plan));
</script>

</body>
</html>
2 changes: 1 addition & 1 deletion src/EFCore.Visualizer/source.extension.vsixmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<MoreInfo>https://github.com/Giorgi/EFCore.Visualizer</MoreInfo>
<GettingStartedGuide>https://github.com/Giorgi/EFCore.Visualizer/blob/main/README.md#usage</GettingStartedGuide>
<Icon>Images\IconSmall.png</Icon>
<Tags>EFCore, SQL Server, PostgreSQL, Visualizer, Query Plan</Tags>
<Tags>EFCore, SQL Server, PostgreSQL, Oracle, Visualizer, Query Plan</Tags>
</Metadata>
<Installation ExtensionType="VSSDK+VisualStudio.Extensibility">
<InstallationTarget Version="[17.9, 18.0)" Id="Microsoft.VisualStudio.Community">
Expand Down
20 changes: 20 additions & 0 deletions src/IQueryableObjectSource/DatabaseProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,24 @@ protected override string ExtractPlanInternal(DbCommand command)
}

internal override string GetPlanDirectory(string baseDirectory) => Path.Combine(baseDirectory, "Postgres");
}

class OracleDatabaseProvider(DbCommand command) : DatabaseProvider(command)
{
protected override string ExtractPlanInternal(DbCommand command)
{
command.CommandText = "EXPLAIN PLAN FOR " + command.CommandText;
command.ExecuteNonQuery();

// Querying the execution plan using DBMS_XPLAN
command.CommandText = "SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY())";
using var reader = command.ExecuteReader();

// Fetching the plan output
var plan = string.Join(Environment.NewLine, reader.Cast<IDataRecord>().Select(r => r.GetString(0)));

return plan;
}

internal override string GetPlanDirectory(string baseDirectory) => Path.Combine(baseDirectory, "Oracle");
}
1 change: 1 addition & 0 deletions src/IQueryableObjectSource/EFCoreQueryableObjectSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ private static DatabaseProvider GetDatabaseProvider(DbCommand command)
{
"Microsoft.Data.SqlClient.SqlCommand" => new SqlServerDatabaseProvider(command),
"Npgsql.NpgsqlCommand" => new PostgresDatabaseProvider(command),
"Oracle.ManagedDataAccess.Client.OracleCommand" => new OracleDatabaseProvider(command),
_ => null
};
}
Expand Down

0 comments on commit 39f1088

Please sign in to comment.