Skip to content

Commit 263a7b1

Browse files
krwqroji
authored andcommitted
Improve LoadExtension to work correctly with dotnet run and lib* named libs
* Improve LoadExtension to work correctly with dotnet run and lib packages * Use [] instead of Array.Empty (cherry picked from commit b1d34dc)
1 parent bd39e43 commit 263a7b1

File tree

1 file changed

+79
-3
lines changed

1 file changed

+79
-3
lines changed

src/Microsoft.Data.Sqlite.Core/SqliteConnection.cs

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ namespace Microsoft.Data.Sqlite
2323
/// <seealso href="https://docs.microsoft.com/dotnet/standard/data/sqlite/async">Async Limitations</seealso>
2424
public partial class SqliteConnection : DbConnection
2525
{
26+
private static readonly bool UseOldBehavior35715 =
27+
AppContext.TryGetSwitch("Microsoft.EntityFrameworkCore.Issue35715", out var enabled35715) && enabled35715;
28+
2629
internal const string MainDatabaseName = "main";
2730

2831
private const int SQLITE_WIN32_DATA_DIRECTORY_TYPE = 1;
@@ -48,6 +51,8 @@ public partial class SqliteConnection : DbConnection
4851
private static readonly StateChangeEventArgs _fromClosedToOpenEventArgs = new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open);
4952
private static readonly StateChangeEventArgs _fromOpenToClosedEventArgs = new StateChangeEventArgs(ConnectionState.Open, ConnectionState.Closed);
5053

54+
private static string[]? NativeDllSearchDirectories;
55+
5156
static SqliteConnection()
5257
{
5358
Type.GetType("SQLitePCL.Batteries_V2, SQLitePCLRaw.batteries_v2")
@@ -626,11 +631,82 @@ public virtual void LoadExtension(string file, string? proc = null)
626631

627632
private void LoadExtensionCore(string file, string? proc)
628633
{
629-
var rc = sqlite3_load_extension(Handle, utf8z.FromString(file), utf8z.FromString(proc), out var errmsg);
630-
if (rc != SQLITE_OK)
634+
if (UseOldBehavior35715)
635+
{
636+
var rc = sqlite3_load_extension(Handle, utf8z.FromString(file), utf8z.FromString(proc), out var errmsg);
637+
if (rc != SQLITE_OK)
638+
{
639+
throw new SqliteException(Resources.SqliteNativeError(rc, errmsg.utf8_to_string()), rc, rc);
640+
}
641+
}
642+
else
643+
{
644+
SqliteException? firstException = null;
645+
foreach (var path in GetLoadExtensionPaths(file))
646+
{
647+
var rc = sqlite3_load_extension(Handle, utf8z.FromString(path), utf8z.FromString(proc), out var errmsg);
648+
if (rc == SQLITE_OK)
649+
{
650+
return;
651+
}
652+
653+
if (firstException == null)
654+
{
655+
// We store the first exception so that error message looks more obvious if file appears in there
656+
firstException = new SqliteException(Resources.SqliteNativeError(rc, errmsg.utf8_to_string()), rc, rc);
657+
}
658+
}
659+
660+
if (firstException != null)
661+
{
662+
throw firstException;
663+
}
664+
}
665+
}
666+
667+
private static IEnumerable<string> GetLoadExtensionPaths(string file)
668+
{
669+
// we always try original input first
670+
yield return file;
671+
672+
string? dirName = Path.GetDirectoryName(file);
673+
674+
// we don't try to guess directories for user, if they pass a path either absolute or relative - they're on their own
675+
if (!string.IsNullOrEmpty(dirName))
631676
{
632-
throw new SqliteException(Resources.SqliteNativeError(rc, errmsg.utf8_to_string()), rc, rc);
677+
yield break;
633678
}
679+
680+
bool shouldTryAddingLibPrefix = !file.StartsWith("lib", StringComparison.Ordinal) && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
681+
682+
if (shouldTryAddingLibPrefix)
683+
{
684+
yield return $"lib{file}";
685+
}
686+
687+
NativeDllSearchDirectories ??= GetNativeDllSearchDirectories();
688+
689+
foreach (string dir in NativeDllSearchDirectories)
690+
{
691+
yield return Path.Combine(dir, file);
692+
693+
if (shouldTryAddingLibPrefix)
694+
{
695+
yield return Path.Combine(dir, $"lib{file}");
696+
}
697+
}
698+
}
699+
700+
private static string[] GetNativeDllSearchDirectories()
701+
{
702+
string? searchDirs = AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES") as string;
703+
704+
if (string.IsNullOrEmpty(searchDirs))
705+
{
706+
return [];
707+
}
708+
709+
return searchDirs!.Split([ Path.PathSeparator ], StringSplitOptions.RemoveEmptyEntries);
634710
}
635711

636712
/// <summary>

0 commit comments

Comments
 (0)