@@ -6,10 +6,13 @@ package export
66import (
77 "archive/zip"
88 "context"
9+ "encoding/csv"
910 "encoding/json"
1011 "fmt"
12+ "io"
1113 "os"
1214 "path/filepath"
15+ "strings"
1316 "testing"
1417 "time"
1518
@@ -95,17 +98,35 @@ func seedTestData(t *testing.T, conn *pgx.Conn) {
9598 ctx := context .Background ()
9699
97100 queries := []string {
98- // Create a test database
99- "CREATE DATABASE IF NOT EXISTS testdb" ,
100- // Create a test table
101- "CREATE TABLE IF NOT EXISTS testdb.test_table (id INT PRIMARY KEY, name STRING)" ,
101+ // Create multiple test databases to verify cross-database table_indexes export
102+ "CREATE DATABASE IF NOT EXISTS testdb1" ,
103+ "CREATE DATABASE IF NOT EXISTS testdb2" ,
104+ "CREATE DATABASE IF NOT EXISTS testdb3" ,
105+
106+ // Create tables in testdb1
107+ "CREATE TABLE IF NOT EXISTS testdb1.users (id INT PRIMARY KEY, username STRING)" ,
108+ "CREATE TABLE IF NOT EXISTS testdb1.orders (id INT PRIMARY KEY, user_id INT, total DECIMAL)" ,
109+
110+ // Create tables in testdb2
111+ "CREATE TABLE IF NOT EXISTS testdb2.products (id INT PRIMARY KEY, name STRING, price DECIMAL)" ,
112+ "CREATE TABLE IF NOT EXISTS testdb2.inventory (product_id INT PRIMARY KEY, quantity INT)" ,
113+
114+ // Create tables in testdb3
115+ "CREATE TABLE IF NOT EXISTS testdb3.logs (id INT PRIMARY KEY, message STRING, created_at TIMESTAMP)" ,
116+
102117 // Insert some data
103- "INSERT INTO testdb.test_table VALUES (1, 'test1'), (2, 'test2')" ,
118+ "INSERT INTO testdb1.users VALUES (1, 'alice'), (2, 'bob')" ,
119+ "INSERT INTO testdb2.products VALUES (1, 'widget', 9.99), (2, 'gadget', 19.99)" ,
120+ "INSERT INTO testdb3.logs VALUES (1, 'test log', now())" ,
121+
104122 // Run some queries to generate statistics
105- "SELECT * FROM testdb.test_table WHERE id = 1" ,
106- "SELECT * FROM testdb.test_table WHERE name = 'test2'" ,
107- // Create a zone configuration
108- "ALTER TABLE testdb.test_table CONFIGURE ZONE USING num_replicas = 1" ,
123+ "SELECT * FROM testdb1.users WHERE id = 1" ,
124+ "SELECT * FROM testdb2.products WHERE price > 10" ,
125+ "SELECT * FROM testdb3.logs LIMIT 1" ,
126+
127+ // Create zone configurations
128+ "ALTER TABLE testdb1.users CONFIGURE ZONE USING num_replicas = 1" ,
129+ "ALTER TABLE testdb2.products CONFIGURE ZONE USING num_replicas = 1" ,
109130 }
110131
111132 for _ , query := range queries {
@@ -116,7 +137,7 @@ func seedTestData(t *testing.T, conn *pgx.Conn) {
116137 // Wait a bit for statistics to be collected
117138 time .Sleep (2 * time .Second )
118139
119- t .Log ("Test data seeded successfully" )
140+ t .Log ("Test data seeded successfully with multiple databases " )
120141}
121142
122143// validateExport checks that the export file contains all expected content
@@ -142,7 +163,9 @@ func validateExport(t *testing.T, zipPath string, version string) {
142163 "crdb_internal.gossip_nodes.csv" : false ,
143164 "crdb_internal.table_indexes.csv" : false ,
144165 "zone_configurations.txt" : false ,
145- "testdb.schema.txt" : false , // Our test database
166+ "testdb1.schema.txt" : false , // Our test databases
167+ "testdb2.schema.txt" : false ,
168+ "testdb3.schema.txt" : false ,
146169 }
147170
148171 // Check all files in zip
@@ -162,6 +185,11 @@ func validateExport(t *testing.T, zipPath string, version string) {
162185 if file .Name == "metadata.json" {
163186 validateMetadataFile (t , file , version )
164187 }
188+
189+ // Validate table_indexes contains data from multiple databases
190+ if file .Name == "crdb_internal.table_indexes.csv" {
191+ validateTableIndexesFile (t , file , version )
192+ }
165193 }
166194
167195 // Ensure all expected files were found
@@ -207,3 +235,69 @@ func validateMetadataFile(t *testing.T, file *zip.File, version string) {
207235
208236 t .Logf (" Cluster version from metadata: %s" , metadata .ClusterVersion )
209237}
238+
239+ // validateTableIndexesFile ensures table_indexes CSV contains data from multiple databases
240+ func validateTableIndexesFile (t * testing.T , file * zip.File , version string ) {
241+ rc , err := file .Open ()
242+ require .NoError (t , err , "Should be able to open table_indexes CSV" )
243+ defer rc .Close ()
244+
245+ // Parse CSV
246+ reader := csv .NewReader (rc )
247+
248+ // Read header
249+ header , err := reader .Read ()
250+ require .NoError (t , err , "Should be able to read CSV header" )
251+
252+ // Find the descriptor_name column index (contains database.schema.table)
253+ descriptorNameIdx := - 1
254+ for i , col := range header {
255+ if col == "descriptor_name" {
256+ descriptorNameIdx = i
257+ break
258+ }
259+ }
260+ require .NotEqual (t , - 1 , descriptorNameIdx , "CSV should have descriptor_name column" )
261+
262+ // Track which databases we've seen
263+ databasesSeen := make (map [string ]bool )
264+
265+ // Read all rows and extract database names
266+ for {
267+ record , err := reader .Read ()
268+ if err == io .EOF {
269+ break
270+ }
271+ require .NoError (t , err , "Should be able to read CSV row" )
272+
273+ if len (record ) > descriptorNameIdx {
274+ descriptorName := record [descriptorNameIdx ]
275+ // descriptor_name format is typically "database.schema.table" or "database.public.table"
276+ parts := strings .Split (descriptorName , "." )
277+ if len (parts ) >= 1 {
278+ database := parts [0 ]
279+ // Track non-system databases
280+ if database != "system" && database != "postgres" && database != "" {
281+ databasesSeen [database ] = true
282+ }
283+ }
284+ }
285+ }
286+
287+ // Verify we have entries from our test databases
288+ expectedDatabases := []string {"testdb1" , "testdb2" , "testdb3" }
289+ foundCount := 0
290+ for _ , db := range expectedDatabases {
291+ if databasesSeen [db ] {
292+ foundCount ++
293+ t .Logf (" ✓ Found table indexes for database: %s" , db )
294+ }
295+ }
296+
297+ // We should see at least 2 of our test databases to prove cross-database querying works
298+ require .GreaterOrEqual (t , foundCount , 2 ,
299+ "table_indexes CSV should contain entries from multiple test databases (found %d, expected at least 2)" ,
300+ foundCount )
301+
302+ t .Logf (" ✓ table_indexes contains data from %d databases (version %s)" , len (databasesSeen ), version )
303+ }
0 commit comments