diff --git a/dbbackup b/dbbackup index bd6ca70..329d319 100755 Binary files a/dbbackup and b/dbbackup differ diff --git a/dbbackup_linux_amd64 b/dbbackup_linux_amd64 index 3719376..329d319 100755 Binary files a/dbbackup_linux_amd64 and b/dbbackup_linux_amd64 differ diff --git a/internal/restore/engine.go b/internal/restore/engine.go index ad3481a..55383b9 100644 --- a/internal/restore/engine.go +++ b/internal/restore/engine.go @@ -351,6 +351,12 @@ func (e *Engine) RestoreCluster(ctx context.Context, archivePath string) error { e.progress.Update(fmt.Sprintf("[%d/%d] Restoring database: %s", i+1, len(entries), dbName)) e.log.Info("Restoring database", "name", dbName, "file", dumpFile) + // Create database first if it doesn't exist + if err := e.ensureDatabaseExists(ctx, dbName); err != nil { + e.log.Warn("Could not ensure database exists", "name", dbName, "error", err) + // Continue anyway - pg_restore can create it + } + if err := e.restorePostgreSQLDump(ctx, dumpFile, dbName, false, false); err != nil { e.log.Error("Failed to restore database", "name", dbName, "error", err) failCount++ @@ -402,6 +408,50 @@ func (e *Engine) restoreGlobals(ctx context.Context, globalsFile string) error { return nil } +// ensureDatabaseExists checks if a database exists and creates it if not +func (e *Engine) ensureDatabaseExists(ctx context.Context, dbName string) error { + // Check if database exists using psql + checkCmd := exec.CommandContext(ctx, "psql", + "-h", e.cfg.Host, + "-p", fmt.Sprintf("%d", e.cfg.Port), + "-U", e.cfg.User, + "-d", "postgres", // Connect to default postgres database + "-tAc", + fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", dbName), + ) + checkCmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password)) + + output, err := checkCmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to check database existence: %w", err) + } + + // If database exists, we're done + if strings.TrimSpace(string(output)) == "1" { + e.log.Info(fmt.Sprintf("Database '%s' already exists", dbName)) + return nil + } + + // Database doesn't exist, create it + e.log.Info(fmt.Sprintf("Creating database '%s'", dbName)) + createCmd := exec.CommandContext(ctx, "psql", + "-h", e.cfg.Host, + "-p", fmt.Sprintf("%d", e.cfg.Port), + "-U", e.cfg.User, + "-d", "postgres", + "-c", fmt.Sprintf("CREATE DATABASE \"%s\"", dbName), + ) + createCmd.Env = append(os.Environ(), fmt.Sprintf("PGPASSWORD=%s", e.cfg.Password)) + + output, err = createCmd.CombinedOutput() + if err != nil { + return fmt.Errorf("failed to create database '%s': %w\nOutput: %s", dbName, err, string(output)) + } + + e.log.Info(fmt.Sprintf("Successfully created database '%s'", dbName)) + return nil +} + // previewClusterRestore shows cluster restore preview func (e *Engine) previewClusterRestore(archivePath string) error { fmt.Println("\n" + strings.Repeat("=", 60))