Skip to content

Commit 00b8249

Browse files
authored
Merge pull request #520 from clidey/claude/issue-502-20250613_182153
fix: Add proper identifier quoting for SQLite3 non-English characters
2 parents 4217f77 + bd682ab commit 00b8249

File tree

6 files changed

+48
-29
lines changed

6 files changed

+48
-29
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
/.idea
22
/.vscode
33
/dev/elasticsearch
4-
DS_Store
4+
DS_Store
5+
.DS_Store
6+
__debug*
7+
*.db

core/src/plugins/gorm/db.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ package gorm_plugin
1818

1919
import (
2020
"fmt"
21+
"net/url"
22+
"strconv"
23+
"time"
24+
2125
"github.com/clidey/whodb/core/src/common"
2226
"github.com/clidey/whodb/core/src/engine"
2327
"github.com/clidey/whodb/core/src/plugins"
2428
"gorm.io/gorm"
25-
"net/url"
26-
"strconv"
27-
"time"
2829
)
2930

3031
const (
@@ -111,11 +112,23 @@ func (p *GormPlugin) ParseConnectionConfig(config *engine.PluginConfig) (*Connec
111112
return nil, err
112113
}
113114

115+
database := config.Credentials.Database
116+
username := config.Credentials.Username
117+
password := config.Credentials.Password
118+
hostname := config.Credentials.Hostname
119+
120+
if p.Type != engine.DatabaseType_Sqlite3 && p.Type != engine.DatabaseType_Postgres {
121+
database = url.PathEscape(database)
122+
username = url.PathEscape(username)
123+
password = url.PathEscape(password)
124+
hostname = url.PathEscape(hostname)
125+
}
126+
114127
input := &ConnectionInput{
115-
Username: url.PathEscape(config.Credentials.Username),
116-
Password: url.PathEscape(config.Credentials.Password),
117-
Database: url.PathEscape(config.Credentials.Database),
118-
Hostname: url.PathEscape(config.Credentials.Hostname),
128+
Username: username,
129+
Password: password,
130+
Database: database,
131+
Hostname: hostname,
119132
Port: port,
120133
ParseTime: parseTime,
121134
Loc: loc,
@@ -135,7 +148,12 @@ func (p *GormPlugin) ParseConnectionConfig(config *engine.PluginConfig) (*Connec
135148
case portKey, parseTimeKey, locKey, allowClearTextPasswordsKey, sslModeKey, httpProtocolKey, readOnlyKey, debugKey, connectionTimeoutKey:
136149
continue
137150
default:
138-
params[record.Key] = url.QueryEscape(record.Value) // todo: this may break for postgres
151+
// PostgreSQL uses libpq connection string format, not URL query parameters
152+
if p.Type == engine.DatabaseType_Postgres {
153+
params[record.Key] = record.Value // Raw value, PostgreSQL plugin will handle escaping
154+
} else {
155+
params[record.Key] = url.QueryEscape(record.Value)
156+
}
139157
}
140158
}
141159
input.ExtraOptions = params

core/src/plugins/postgres/db.go

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,33 @@ package postgres
1818

1919
import (
2020
"fmt"
21+
"net/url"
2122
"strings"
2223

2324
"github.com/clidey/whodb/core/src/engine"
2425
"gorm.io/driver/postgres"
2526
"gorm.io/gorm"
2627
)
2728

28-
func escape(x string) string {
29-
return strings.ReplaceAll(x, "'", "\\'")
30-
}
31-
3229
func (p *PostgresPlugin) DB(config *engine.PluginConfig) (*gorm.DB, error) {
3330
connectionInput, err := p.ParseConnectionConfig(config)
3431
if err != nil {
3532
return nil, err
3633
}
3734

38-
host := escape(connectionInput.Hostname)
39-
username := escape(connectionInput.Username)
40-
password := escape(connectionInput.Password)
41-
database := escape(connectionInput.Database)
35+
dsn := fmt.Sprintf("postgresql://%s:%s@%s:%v/%s",
36+
url.QueryEscape(connectionInput.Username),
37+
url.QueryEscape(connectionInput.Password),
38+
url.QueryEscape(connectionInput.Hostname),
39+
connectionInput.Port,
40+
url.QueryEscape(connectionInput.Database))
4241

43-
params := strings.Builder{}
4442
if connectionInput.ExtraOptions != nil {
43+
params := url.Values{}
4544
for key, value := range connectionInput.ExtraOptions {
46-
params.WriteString(fmt.Sprintf("%v='%v' ", strings.ToLower(key), escape(value)))
45+
params.Add(strings.ToLower(key), value)
4746
}
48-
}
49-
50-
dsn := fmt.Sprintf("host='%v' user='%v' password='%v' dbname='%v' port='%v'",
51-
host, username, password, database, connectionInput.Port)
52-
53-
if params.Len() > 0 {
54-
dsn = fmt.Sprintf("%v %v", dsn, params.String())
47+
dsn += "?" + params.Encode()
5548
}
5649

5750
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

core/src/plugins/sqlite3/add.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func (p *Sqlite3Plugin) GetCreateTableQuery(schema string, storageUnit string, c
2626
var columnDefs []string
2727

2828
for _, column := range columns {
29-
parts := []string{column.Key}
29+
parts := []string{p.EscapeIdentifier(column.Key)}
3030

3131
// Handle primary key with INTEGER type for auto-increment
3232
if primary, ok := column.Extra["primary"]; ok && primary == "true" {
@@ -47,5 +47,5 @@ func (p *Sqlite3Plugin) GetCreateTableQuery(schema string, storageUnit string, c
4747
columnDefs = append(columnDefs, strings.Join(parts, " "))
4848
}
4949

50-
return fmt.Sprintf("CREATE TABLE %s (%s)", storageUnit, strings.Join(columnDefs, ", "))
50+
return fmt.Sprintf("CREATE TABLE %s (%s)", p.EscapeIdentifier(storageUnit), strings.Join(columnDefs, ", "))
5151
}

core/src/plugins/sqlite3/db.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ func (p *Sqlite3Plugin) DB(config *engine.PluginConfig) (*gorm.DB, error) {
4545
}
4646
database := connectionInput.Database
4747
fileNameDatabase := filepath.Join(getDefaultDirectory(), database)
48+
fileNameDatabase, err = filepath.EvalSymlinks(fileNameDatabase)
49+
if err != nil {
50+
return nil, err
51+
}
4852
if !strings.HasPrefix(fileNameDatabase, getDefaultDirectory()) {
4953
return nil, errDoesNotExist
5054
}

core/src/plugins/sqlite3/sqlite3.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ func (p *Sqlite3Plugin) GetTableNameAndAttributes(rows *sql.Rows, db *gorm.DB) (
9090
}
9191

9292
var rowCount int64
93-
rowCountRow := db.Raw(fmt.Sprintf("SELECT COUNT(*) FROM '%s'", tableName)).Row()
93+
escapedTableName := p.EscapeIdentifier(tableName)
94+
rowCountRow := db.Raw(fmt.Sprintf("SELECT COUNT(*) FROM %s", escapedTableName)).Row()
9495
err := rowCountRow.Scan(&rowCount)
9596
if err != nil {
9697
return "", nil

0 commit comments

Comments
 (0)