Skip to content

Commit 4989efd

Browse files
authored
fix(indexes): use lib/pq array parser for column names with special characters
fix(indexes): use lib/pq array parser for column names with special characters
2 parents e92a53e + 2d5330f commit 4989efd

File tree

2 files changed

+99
-8
lines changed

2 files changed

+99
-8
lines changed

integration_test.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,100 @@ func TestIntegration_App_ListIndexes(t *testing.T) {
436436
assert.True(t, foundEmailIdx, "Should find email index")
437437
}
438438

439+
func TestIntegration_App_ListIndexes_SpecialCharacters(t *testing.T) {
440+
_, connectionString, cleanup := setupTestContainer(t)
441+
defer cleanup()
442+
443+
db, err := sql.Open("postgres", connectionString)
444+
require.NoError(t, err)
445+
defer db.Close()
446+
447+
ctx := context.Background()
448+
449+
// Create test schema
450+
testSchema := "test_special_chars"
451+
_, err = db.ExecContext(ctx, fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", testSchema))
452+
require.NoError(t, err)
453+
_, err = db.ExecContext(ctx, fmt.Sprintf("CREATE SCHEMA %s", testSchema))
454+
require.NoError(t, err)
455+
456+
// Create table with columns containing special characters
457+
_, err = db.ExecContext(ctx, fmt.Sprintf(`
458+
CREATE TABLE %s.test_table (
459+
id SERIAL PRIMARY KEY,
460+
"Column Name" VARCHAR(255),
461+
"col,with,commas" VARCHAR(255),
462+
"col{value}" VARCHAR(255),
463+
"col}data" VARCHAR(255),
464+
normal_col VARCHAR(255)
465+
)
466+
`, testSchema))
467+
require.NoError(t, err)
468+
469+
// Create indexes with special character column names
470+
_, err = db.ExecContext(ctx, fmt.Sprintf(`
471+
CREATE INDEX idx_quoted_name ON %s.test_table ("Column Name")
472+
`, testSchema))
473+
require.NoError(t, err)
474+
475+
_, err = db.ExecContext(ctx, fmt.Sprintf(`
476+
CREATE INDEX idx_with_commas ON %s.test_table ("col,with,commas", normal_col)
477+
`, testSchema))
478+
require.NoError(t, err)
479+
480+
_, err = db.ExecContext(ctx, fmt.Sprintf(`
481+
CREATE INDEX idx_braces ON %s.test_table ("col{value}", "col}data")
482+
`, testSchema))
483+
require.NoError(t, err)
484+
485+
// Test with app
486+
appInstance, err := app.New()
487+
require.NoError(t, err)
488+
defer appInstance.Disconnect()
489+
490+
err = appInstance.Connect(connectionString)
491+
require.NoError(t, err)
492+
493+
indexes, err := appInstance.ListIndexes(testSchema, "test_table")
494+
assert.NoError(t, err)
495+
assert.NotEmpty(t, indexes)
496+
497+
// Verify each index is parsed correctly
498+
indexMap := make(map[string]*app.IndexInfo)
499+
for _, idx := range indexes {
500+
indexMap[idx.Name] = idx
501+
}
502+
503+
// Check idx_quoted_name
504+
if idx, ok := indexMap["idx_quoted_name"]; ok {
505+
assert.Len(t, idx.Columns, 1, "idx_quoted_name should have 1 column")
506+
assert.Equal(t, "Column Name", idx.Columns[0], "Column name should be 'Column Name'")
507+
} else {
508+
t.Error("idx_quoted_name not found")
509+
}
510+
511+
// Check idx_with_commas - should have 2 columns, not split by commas inside quotes
512+
if idx, ok := indexMap["idx_with_commas"]; ok {
513+
assert.Len(t, idx.Columns, 2, "idx_with_commas should have exactly 2 columns")
514+
assert.Contains(t, idx.Columns, "col,with,commas", "Should contain column with commas")
515+
assert.Contains(t, idx.Columns, "normal_col", "Should contain normal_col")
516+
} else {
517+
t.Error("idx_with_commas not found")
518+
}
519+
520+
// Check idx_braces
521+
if idx, ok := indexMap["idx_braces"]; ok {
522+
assert.Len(t, idx.Columns, 2, "idx_braces should have 2 columns")
523+
assert.Contains(t, idx.Columns, "col{value}", "Should contain 'col{value}'")
524+
assert.Contains(t, idx.Columns, "col}data", "Should contain 'col}data'")
525+
} else {
526+
t.Error("idx_braces not found")
527+
}
528+
529+
// Cleanup
530+
_, _ = db.ExecContext(ctx, fmt.Sprintf("DROP SCHEMA IF EXISTS %s CASCADE", testSchema))
531+
}
532+
439533
func TestIntegration_App_ExplainQuery(t *testing.T) {
440534
_, connectionString, cleanup := setupTestDatabase(t)
441535
defer cleanup()

internal/app/client.go

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"fmt"
88
"strings"
99

10-
_ "github.com/lib/pq"
10+
"github.com/lib/pq"
1111
)
1212

1313
// PostgreSQLClientImpl implements the PostgreSQLClient interface.
@@ -325,19 +325,16 @@ func (c *PostgreSQLClientImpl) ListIndexes(schema, table string) ([]*IndexInfo,
325325
var indexes []*IndexInfo
326326
for rows.Next() {
327327
var index IndexInfo
328-
var columnsStr string
328+
var columns pq.StringArray
329329
if err := rows.Scan(
330-
&index.Name, &index.Table, &columnsStr,
330+
&index.Name, &index.Table, &columns,
331331
&index.IsUnique, &index.IsPrimary, &index.IndexType,
332332
); err != nil {
333333
return nil, fmt.Errorf("failed to scan index row: %w", err)
334334
}
335335

336-
// Parse column array from PostgreSQL format
337-
columnsStr = strings.Trim(columnsStr, "{}")
338-
if columnsStr != "" {
339-
index.Columns = strings.Split(columnsStr, ",")
340-
}
336+
// Convert pq.StringArray to []string
337+
index.Columns = []string(columns)
341338

342339
indexes = append(indexes, &index)
343340
}

0 commit comments

Comments
 (0)