Use psql subprocess to execute schema script - handles psql meta-commands
This commit is contained in:
+61
-10
@@ -8,6 +8,7 @@ namespace Jellyfin.Database.Providers.Postgres;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -418,24 +419,74 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
||||
|
||||
try
|
||||
{
|
||||
var schemaScript = await File.ReadAllTextAsync(schemaScriptPath, cancellationToken).ConfigureAwait(false);
|
||||
// The SQL file contains psql meta-commands (\restrict, etc.) that can't be executed via ExecuteNonQuery
|
||||
// We need to use psql subprocess instead
|
||||
var connectionString = connection.ConnectionString;
|
||||
var builder = new NpgsqlConnectionStringBuilder(connectionString);
|
||||
|
||||
// Split script by statement terminator and execute each part
|
||||
// PostgreSQL dump scripts may have multiple statements
|
||||
await using (var command = connection.CreateCommand())
|
||||
// Build psql command
|
||||
var psqlArgs = $"-h {builder.Host} -p {builder.Port} -U {builder.Username} -d {builder.Database} -f \"{schemaScriptPath}\"";
|
||||
|
||||
logger.LogInformation("Executing via psql: psql {Args}", psqlArgs.Replace(builder.Password ?? string.Empty, "***", StringComparison.Ordinal));
|
||||
|
||||
var psqlProcess = new System.Diagnostics.Process
|
||||
{
|
||||
command.CommandText = schemaScript;
|
||||
command.CommandTimeout = 600; // 10 minutes
|
||||
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
||||
StartInfo = new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = "psql",
|
||||
Arguments = psqlArgs,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
RedirectStandardInput = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
}
|
||||
};
|
||||
|
||||
// Set password via environment variable
|
||||
if (!string.IsNullOrEmpty(builder.Password))
|
||||
{
|
||||
psqlProcess.StartInfo.EnvironmentVariables["PGPASSWORD"] = builder.Password;
|
||||
}
|
||||
|
||||
logger.LogInformation("✅ Successfully initialized database from SQL script");
|
||||
logger.LogInformation("Database is ready. You can now start Jellyfin.");
|
||||
psqlProcess.Start();
|
||||
|
||||
// Read output
|
||||
var output = await psqlProcess.StandardOutput.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
||||
var error = await psqlProcess.StandardError.ReadToEndAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
await psqlProcess.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
|
||||
|
||||
if (psqlProcess.ExitCode == 0)
|
||||
{
|
||||
logger.LogInformation("✅ Successfully initialized database from SQL script via psql");
|
||||
logger.LogInformation("Database is ready. You can now start Jellyfin.");
|
||||
if (!string.IsNullOrWhiteSpace(output))
|
||||
{
|
||||
logger.LogDebug("psql output: {Output}", output);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogError("psql exited with code {ExitCode}", psqlProcess.ExitCode);
|
||||
if (!string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
logger.LogError("psql error: {Error}", error);
|
||||
}
|
||||
throw new InvalidOperationException($"psql failed with exit code {psqlProcess.ExitCode}. Error: {error}");
|
||||
}
|
||||
}
|
||||
catch (System.ComponentModel.Win32Exception psqlNotFound)
|
||||
{
|
||||
// psql not found in PATH - fallback to manual instructions
|
||||
logger.LogWarning(psqlNotFound, "psql command not found in PATH. Cannot automatically initialize database.");
|
||||
logger.LogError("Please run the SQL script manually: psql -U postgres -d jellyfin_testdata -f {Path}", schemaScriptPath);
|
||||
throw new FileNotFoundException("psql command not found. Please install PostgreSQL client tools and ensure psql is in your PATH, or run the SQL script manually.", psqlNotFound);
|
||||
}
|
||||
catch (Exception scriptEx)
|
||||
{
|
||||
logger.LogError(scriptEx, "Failed to execute schema creation script");
|
||||
logger.LogError("Please run the SQL script manually: psql -U jellyfin -d jellyfin -f {Path}", schemaScriptPath);
|
||||
logger.LogError("Please run the SQL script manually: psql -U postgres -d jellyfin_testdata -f {Path}", schemaScriptPath);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user