./xdumpgo --version
Extra Quality Tip: Use Go 1.20+ to avoid memory alignment bugs.
We need a writer that handles escaping and SQL formatting on the fly.
package mainimport ( "database/sql" "fmt" "io" "os" "strings" xdumpgo tutorial extra quality
_ "github.com/lib/pq" // Example using PostgreSQL)
// SQLDumper handles the streaming dump process type SQLDumper struct db *sql.DB output io.Writer
func NewSQLDumper(db *sql.DB, output io.Writer) *SQLDumper return &SQLDumperdb: db, output: output Extra Quality Tip : Use Go 1
// DumpTable streams a specific table to the output writer func (d *SQLDumper) DumpTable(tableName string) error { // 1. Setup the streaming query // We use a transaction with READ ONLY to ensure consistency tx, err := d.db.Begin() if err != nil return fmt.Errorf("failed to begin transaction: %w", err) defer tx.Rollback() // Safe to rollback read-only tx
// 2. Execute Query // For true "extra quality", you would implement cursor/pagination here // for massive datasets, but Rows() is a streaming iterator in Go. rows, err := tx.Query(fmt.Sprintf("SELECT * FROM %s", tableName)) if err != nil return fmt.Errorf("query failed: %w", err) defer rows.Close() columns, err := rows.Columns() if err != nil return err // 3. Write Header header := fmt.Sprintf("\n-- Dumping data for table: %s\n", tableName) d.output.Write([]byte(header)) // 4. Stream Processing // We create a slice of empty interfaces to hold raw pointers values := make([]interface{}, len(columns)) valuePtrs := make([]interface{}, len(columns)) for i := range columns valuePtrs[i] = &values[i] for rows.Next() // Scan into pointers if err := rows.Scan(valuePtrs...); err != nil return err // Build the INSERT statement dynamically if err := d.writeInsert(tableName, columns, valuePtrs); err != nil return err return rows.Err()}
// writeInsert constructs and writes a single INSERT statement func (d *SQLDumper) writeInsert(table string, cols []string, vals []interface{}) error var sb strings.Builder We need a writer that handles escaping and
sb.WriteString(fmt.Sprintf("INSERT INTO %s (", table)) for i, col := range cols if i > 0 sb.WriteString(", ") sb.WriteString(col) sb.WriteString(") VALUES (") for i, val := range vals if i > 0 sb.WriteString(", ") // Type switching for proper SQL escaping switch v := val.(type) case *string: // In production, use proper escaping libraries to prevent SQL injection in dumps sb.WriteString(fmt.Sprintf("'%s'", *v)) case *int, *int64, *float64: sb.WriteString(fmt.Sprintf("%v", v)) case *bool: if *v sb.WriteString("TRUE") else sb.WriteString("FALSE") case nil: sb.WriteString("NULL") default: // Handle byte arrays or unknown types sb.WriteString(fmt.Sprintf("'%v'", v)) sb.WriteString(");\n") _, err := d.output.Write([]byte(sb.String())) return errfunc main() connStr := "user=postgres dbname=mydb sslmode=disable" db, err := sql.Open("postgres", connStr) if err != nil panic(err) defer db.Close()
// Create output file f, err := os.Create("dump.sql") if err != nil panic(err) defer f.Close() dumper := NewSQLDumper(db, f) fmt.Println("Starting Extra Quality Dump...") if err := dumper.DumpTable("users"); err != nil panic(err) fmt.Println("Dump completed successfully.")
./xdumpgo dump \
--pid 1234 \
--output high_quality.dump \
--full-page \
--ignore-paged \
--preserve-perms \
--verify-checksum \
--thread-sync
| Flag | Purpose |
|------|---------|
| --full-page | Dump entire pages, not just requested ranges |
| --ignore-paged | Skip swapped-out pages (prevents corrupted data) |
| --preserve-perms | Store original memory permissions |
| --verify-checksum | Calculate SHA256 after dump |
| --thread-sync | Suspend threads during dump (atomic snapshot) |
./xdumpgo --version
Extra Quality Tip: Use Go 1.20+ to avoid memory alignment bugs.
We need a writer that handles escaping and SQL formatting on the fly.
package mainimport ( "database/sql" "fmt" "io" "os" "strings"
_ "github.com/lib/pq" // Example using PostgreSQL)
// SQLDumper handles the streaming dump process type SQLDumper struct db *sql.DB output io.Writer
func NewSQLDumper(db *sql.DB, output io.Writer) *SQLDumper return &SQLDumperdb: db, output: output
// DumpTable streams a specific table to the output writer func (d *SQLDumper) DumpTable(tableName string) error { // 1. Setup the streaming query // We use a transaction with READ ONLY to ensure consistency tx, err := d.db.Begin() if err != nil return fmt.Errorf("failed to begin transaction: %w", err) defer tx.Rollback() // Safe to rollback read-only tx
// 2. Execute Query // For true "extra quality", you would implement cursor/pagination here // for massive datasets, but Rows() is a streaming iterator in Go. rows, err := tx.Query(fmt.Sprintf("SELECT * FROM %s", tableName)) if err != nil return fmt.Errorf("query failed: %w", err) defer rows.Close() columns, err := rows.Columns() if err != nil return err // 3. Write Header header := fmt.Sprintf("\n-- Dumping data for table: %s\n", tableName) d.output.Write([]byte(header)) // 4. Stream Processing // We create a slice of empty interfaces to hold raw pointers values := make([]interface{}, len(columns)) valuePtrs := make([]interface{}, len(columns)) for i := range columns valuePtrs[i] = &values[i] for rows.Next() // Scan into pointers if err := rows.Scan(valuePtrs...); err != nil return err // Build the INSERT statement dynamically if err := d.writeInsert(tableName, columns, valuePtrs); err != nil return err return rows.Err()}
// writeInsert constructs and writes a single INSERT statement func (d *SQLDumper) writeInsert(table string, cols []string, vals []interface{}) error var sb strings.Builder
sb.WriteString(fmt.Sprintf("INSERT INTO %s (", table)) for i, col := range cols if i > 0 sb.WriteString(", ") sb.WriteString(col) sb.WriteString(") VALUES (") for i, val := range vals if i > 0 sb.WriteString(", ") // Type switching for proper SQL escaping switch v := val.(type) case *string: // In production, use proper escaping libraries to prevent SQL injection in dumps sb.WriteString(fmt.Sprintf("'%s'", *v)) case *int, *int64, *float64: sb.WriteString(fmt.Sprintf("%v", v)) case *bool: if *v sb.WriteString("TRUE") else sb.WriteString("FALSE") case nil: sb.WriteString("NULL") default: // Handle byte arrays or unknown types sb.WriteString(fmt.Sprintf("'%v'", v)) sb.WriteString(");\n") _, err := d.output.Write([]byte(sb.String())) return errfunc main() connStr := "user=postgres dbname=mydb sslmode=disable" db, err := sql.Open("postgres", connStr) if err != nil panic(err) defer db.Close()
// Create output file f, err := os.Create("dump.sql") if err != nil panic(err) defer f.Close() dumper := NewSQLDumper(db, f) fmt.Println("Starting Extra Quality Dump...") if err := dumper.DumpTable("users"); err != nil panic(err) fmt.Println("Dump completed successfully.")
./xdumpgo dump \
--pid 1234 \
--output high_quality.dump \
--full-page \
--ignore-paged \
--preserve-perms \
--verify-checksum \
--thread-sync
| Flag | Purpose |
|------|---------|
| --full-page | Dump entire pages, not just requested ranges |
| --ignore-paged | Skip swapped-out pages (prevents corrupted data) |
| --preserve-perms | Store original memory permissions |
| --verify-checksum | Calculate SHA256 after dump |
| --thread-sync | Suspend threads during dump (atomic snapshot) |