| 43 | var null = []byte("null") |
| 44 | |
| 45 | func (q *Query) Sanitize(args ...any) (string, error) { |
| 46 | argUse := make([]bool, len(args)) |
| 47 | buf := bufPool.get() |
| 48 | defer bufPool.put(buf) |
| 49 | |
| 50 | for _, part := range q.Parts { |
| 51 | switch part := part.(type) { |
| 52 | case string: |
| 53 | buf.WriteString(part) |
| 54 | case int: |
| 55 | argIdx := part - 1 |
| 56 | var p []byte |
| 57 | if argIdx < 0 { |
| 58 | return "", fmt.Errorf("first sql argument must be > 0") |
| 59 | } |
| 60 | |
| 61 | if argIdx >= len(args) { |
| 62 | return "", fmt.Errorf("insufficient arguments") |
| 63 | } |
| 64 | |
| 65 | // Prevent SQL injection via Line Comment Creation |
| 66 | // https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p |
| 67 | buf.WriteByte(' ') |
| 68 | |
| 69 | arg := args[argIdx] |
| 70 | switch arg := arg.(type) { |
| 71 | case nil: |
| 72 | p = null |
| 73 | case int64: |
| 74 | p = strconv.AppendInt(buf.AvailableBuffer(), arg, 10) |
| 75 | case float64: |
| 76 | p = strconv.AppendFloat(buf.AvailableBuffer(), arg, 'f', -1, 64) |
| 77 | case bool: |
| 78 | p = strconv.AppendBool(buf.AvailableBuffer(), arg) |
| 79 | case []byte: |
| 80 | p = QuoteBytes(buf.AvailableBuffer(), arg) |
| 81 | case string: |
| 82 | p = QuoteString(buf.AvailableBuffer(), arg) |
| 83 | case time.Time: |
| 84 | p = arg.Truncate(time.Microsecond). |
| 85 | AppendFormat(buf.AvailableBuffer(), "'2006-01-02 15:04:05.999999999Z07:00:00'") |
| 86 | default: |
| 87 | return "", fmt.Errorf("invalid arg type: %T", arg) |
| 88 | } |
| 89 | argUse[argIdx] = true |
| 90 | |
| 91 | buf.Write(p) |
| 92 | |
| 93 | // Prevent SQL injection via Line Comment Creation |
| 94 | // https://github.com/jackc/pgx/security/advisories/GHSA-m7wr-2xf7-cm9p |
| 95 | buf.WriteByte(' ') |
| 96 | default: |
| 97 | return "", fmt.Errorf("invalid Part type: %T", part) |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | for i, used := range argUse { |
| 102 | if !used { |