Skip to content

Commit c7e9fee

Browse files
authored
Merge pull request #63 from ShiftLeftSecurity/chipaca/escape-args-escape-question-mark
db/connection: support escaping placeholders
2 parents a62c55b + 4720c2d commit c7e9fee

File tree

14 files changed

+621
-6
lines changed

14 files changed

+621
-6
lines changed

db/connection/connection.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,20 +211,34 @@ func (f *FlexibleTransaction) RollbackTransaction(ctx context.Context) error {
211211
}
212212

213213
// EscapeArgs return the query and args with the argument placeholder escaped.
214+
//
215+
// The argument placeholder is `?`. If you need an actual `?` in the output, you
216+
// can input `\?`.If you need an actual `\` in the output, input `\\`.
214217
func EscapeArgs(query string, args []interface{}) (string, []interface{}, error) {
215218
// TODO: make this a bit less ugly
216-
// TODO: identify escaped question marks
217219
queryWithArgs := &strings.Builder{}
218220
argCounter := 1
221+
escaped := false
219222
for _, queryChar := range query {
220-
if queryChar == '?' {
221-
queryWithArgs.WriteRune('$')
222-
queryWithArgs.WriteString(strconv.Itoa(argCounter))
223-
argCounter++
224-
} else {
223+
if escaped {
225224
queryWithArgs.WriteRune(queryChar)
225+
escaped = false
226+
} else {
227+
switch queryChar {
228+
case '\\':
229+
escaped = true
230+
case '?':
231+
queryWithArgs.WriteRune('$')
232+
queryWithArgs.WriteString(strconv.Itoa(argCounter))
233+
argCounter++
234+
default:
235+
queryWithArgs.WriteRune(queryChar)
236+
}
226237
}
227238
}
239+
if escaped {
240+
return "", nil, errors.New("the query ends with an escape")
241+
}
228242
if len(args) != argCounter-1 {
229243
return "", nil, errors.Errorf("the query has %d args but %d were passed: \n %q \n %#v",
230244
argCounter-1, len(args), queryWithArgs, args)

db/connection/connection_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package connection
33
import (
44
"context"
55
"testing"
6+
7+
"github.com/go-test/deep"
68
)
79

810
type fakeConn struct {
@@ -188,3 +190,25 @@ func TestFlexibleTransactionRecursive(t *testing.T) {
188190
t.FailNow()
189191
}
190192
}
193+
194+
func TestEscapeArgsOK(t *testing.T) {
195+
for in, out := range map[string]string{
196+
"from ? where ?=?": "from $1 where $2=$3",
197+
"from ? where ? \\? ?": "from $1 where $2 ? $3",
198+
`\\??\??`: `\$1$2?$3`,
199+
} {
200+
t.Run("", func(t *testing.T) {
201+
args := []interface{}{"hello", 1, 42.}
202+
got, gotArgs, err := EscapeArgs(in, args)
203+
if err != nil {
204+
t.Fatal(err)
205+
}
206+
if diff := deep.Equal(args, gotArgs); diff != nil {
207+
t.Fatal(err)
208+
}
209+
if got != out {
210+
t.Errorf("expected %q, got %q", out, got)
211+
}
212+
})
213+
}
214+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/ShiftLeftSecurity/gaum/v2
33
go 1.15
44

55
require (
6+
github.com/go-test/deep v1.0.8
67
github.com/jackc/pgconn v1.8.1
78
github.com/jackc/pgproto3/v2 v2.0.7 // indirect
89
github.com/jackc/pgx/v4 v4.11.0

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
6767
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
6868
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
6969
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
70+
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
71+
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
7072
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
7173
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
7274
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=

vendor/github.com/go-test/deep/.gitignore

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/go-test/deep/.travis.yml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/go-test/deep/CHANGES.md

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/go-test/deep/LICENSE

Lines changed: 21 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/go-test/deep/README.md

Lines changed: 51 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/github.com/go-test/deep/SECURITY.md

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)