Skip to content

Commit

Permalink
Fix update SET part to handle commas
Browse files Browse the repository at this point in the history
  • Loading branch information
stuioco authored and tommysitu committed Sep 1, 2024
1 parent 158a75d commit 165a6e4
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 6 deletions.
54 changes: 48 additions & 6 deletions core/templating/datasource_sql_over_csv.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,60 @@ func trimQuotes(s string) string {
// parseSetClauses parses the SET part of an UPDATE query
func parseSetClauses(setPart string, headers []string) (map[string]string, error) {
setClauses := make(map[string]string)
parts := strings.Split(setPart, ",")
parts, err := splitOnCommasOutsideQuotes(setPart)
if err != nil {
return nil, err
}

for _, part := range parts {
keyValue := strings.Split(strings.TrimSpace(part), "=")
if !stringExists(headers, strings.TrimSpace(keyValue[0])) {
return nil, errors.New("invalid column provided: " + strings.TrimSpace(keyValue[0]))
} else if len(keyValue) == 2 {
setClauses[strings.TrimSpace(keyValue[0])] = trimQuotes(strings.TrimSpace(keyValue[1]))
keyValue := strings.SplitN(strings.TrimSpace(part), "=", 2)
if len(keyValue) != 2 {
return nil, errors.New("invalid SET clause: " + part)
}
key := strings.TrimSpace(keyValue[0])
value := strings.TrimSpace(keyValue[1])

if !stringExists(headers, key) {
return nil, errors.New("invalid column provided: " + key)
}
setClauses[key] = trimQuotes(value)
}
return setClauses, nil
}

// splitOnCommasOutsideQuotes splits a string by commas only if the commas are outside of quotes
func splitOnCommasOutsideQuotes(s string) ([]string, error) {
var parts []string
var sb strings.Builder
var inQuotes bool
var quoteChar rune

for _, r := range s {
switch {
case r == '\'' || r == '"':
if inQuotes {
if r == quoteChar {
inQuotes = false
}
} else {
inQuotes = true
quoteChar = r
}
sb.WriteRune(r)
case r == ',' && !inQuotes:
parts = append(parts, sb.String())
sb.Reset()
default:
sb.WriteRune(r)
}
}

// Add the last part
parts = append(parts, sb.String())

return parts, nil
}

// parseConditions parses the WHERE part of the query into a slice of Conditions and returns an error if any issues are found.
func parseConditions(wherePart string) ([]Condition, error) {
conditions := []Condition{}
Expand Down
5 changes: 5 additions & 0 deletions core/templating/datasource_sql_over_csv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func TestParseCommand(t *testing.T) {
expected: SQLStatement{Type: "UPDATE", Conditions: []Condition{{Column: "name", Operator: "==", Value: "John Doe"}}, SetClauses: map[string]string{"age": "35"}, DataSourceName: "employees"},
expectError: false,
},
{
query: "UPDATE employees SET department = 'Engineering, Marketing' WHERE name == 'John Doe'",
expected: SQLStatement{Type: "UPDATE", Conditions: []Condition{{Column: "name", Operator: "==", Value: "John Doe"}}, SetClauses: map[string]string{"department": "Engineering, Marketing"}, DataSourceName: "employees"},
expectError: false,
},
{
query: "DELETE FROM employees WHERE age < '30'",
expected: SQLStatement{Type: "DELETE", Conditions: []Condition{{Column: "age", Operator: "<", Value: "30"}}, DataSourceName: "employees"},
Expand Down

0 comments on commit 165a6e4

Please sign in to comment.