Use psql subprocess to execute schema script - handles psql meta-commands
This commit is contained in:
@@ -3,7 +3,7 @@
|
|||||||
"operationId": "02bc6448-a69d-4ff4-a0ec-0db07ec3a09a",
|
"operationId": "02bc6448-a69d-4ff4-a0ec-0db07ec3a09a",
|
||||||
"description": "Upgrade solution or project to new version of .NET",
|
"description": "Upgrade solution or project to new version of .NET",
|
||||||
"startTime": "2026-03-05T22:18:32.3921759Z",
|
"startTime": "2026-03-05T22:18:32.3921759Z",
|
||||||
"lastUpdateTime": "2026-03-08T15:04:52.4729284Z",
|
"lastUpdateTime": "2026-03-08T15:11:47.2281903Z",
|
||||||
"stage": "Execution",
|
"stage": "Execution",
|
||||||
"properties": {},
|
"properties": {},
|
||||||
"folderPath": ""
|
"folderPath": ""
|
||||||
|
|||||||
+61
-10
@@ -8,6 +8,7 @@ namespace Jellyfin.Database.Providers.Postgres;
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -418,24 +419,74 @@ public sealed class PostgresDatabaseProvider : IJellyfinDatabaseProvider
|
|||||||
|
|
||||||
try
|
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
|
// Build psql command
|
||||||
// PostgreSQL dump scripts may have multiple statements
|
var psqlArgs = $"-h {builder.Host} -p {builder.Port} -U {builder.Username} -d {builder.Database} -f \"{schemaScriptPath}\"";
|
||||||
await using (var command = connection.CreateCommand())
|
|
||||||
|
logger.LogInformation("Executing via psql: psql {Args}", psqlArgs.Replace(builder.Password ?? string.Empty, "***", StringComparison.Ordinal));
|
||||||
|
|
||||||
|
var psqlProcess = new System.Diagnostics.Process
|
||||||
{
|
{
|
||||||
command.CommandText = schemaScript;
|
StartInfo = new System.Diagnostics.ProcessStartInfo
|
||||||
command.CommandTimeout = 600; // 10 minutes
|
{
|
||||||
await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
|
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");
|
psqlProcess.Start();
|
||||||
logger.LogInformation("Database is ready. You can now start Jellyfin.");
|
|
||||||
|
// 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)
|
catch (Exception scriptEx)
|
||||||
{
|
{
|
||||||
logger.LogError(scriptEx, "Failed to execute schema creation script");
|
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;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user