aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/xorm.io/xorm/internal/statements/statement_args.go
blob: 64089c1e01cebde9861d87f501dc17d08ad95dca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Copyright 2019 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package statements

import (
	"fmt"
	"reflect"
	"strings"
	"time"

	"xorm.io/builder"
	"xorm.io/xorm/schemas"
)

func quoteNeeded(a interface{}) bool {
	switch a.(type) {
	case int, int8, int16, int32, int64:
		return false
	case uint, uint8, uint16, uint32, uint64:
		return false
	case float32, float64:
		return false
	case bool:
		return false
	case string:
		return true
	case time.Time, *time.Time:
		return true
	case builder.Builder, *builder.Builder:
		return false
	}

	t := reflect.TypeOf(a)
	switch t.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return false
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return false
	case reflect.Float32, reflect.Float64:
		return false
	case reflect.Bool:
		return false
	case reflect.String:
		return true
	}

	return true
}

func convertStringSingleQuote(arg string) string {
	return "'" + strings.Replace(arg, "'", "''", -1) + "'"
}

func convertString(arg string) string {
	var buf strings.Builder
	buf.WriteRune('\'')
	for _, c := range arg {
		if c == '\\' || c == '\'' {
			buf.WriteRune('\\')
		}
		buf.WriteRune(c)
	}
	buf.WriteRune('\'')
	return buf.String()
}

func convertArg(arg interface{}, convertFunc func(string) string) string {
	if quoteNeeded(arg) {
		argv := fmt.Sprintf("%v", arg)
		return convertFunc(argv)
	}

	return fmt.Sprintf("%v", arg)
}

const insertSelectPlaceHolder = true

// WriteArg writes an arg
func (statement *Statement) WriteArg(w *builder.BytesWriter, arg interface{}) error {
	switch argv := arg.(type) {
	case *builder.Builder:
		if _, err := w.WriteString("("); err != nil {
			return err
		}
		if err := argv.WriteTo(w); err != nil {
			return err
		}
		if _, err := w.WriteString(")"); err != nil {
			return err
		}
	default:
		if insertSelectPlaceHolder {
			if err := w.WriteByte('?'); err != nil {
				return err
			}
			if v, ok := arg.(bool); ok && statement.dialect.URI().DBType == schemas.MSSQL {
				if v {
					w.Append(1)
				} else {
					w.Append(0)
				}
			} else {
				w.Append(arg)
			}
		} else {
			var convertFunc = convertStringSingleQuote
			if statement.dialect.URI().DBType == schemas.MYSQL {
				convertFunc = convertString
			}
			if _, err := w.WriteString(convertArg(arg, convertFunc)); err != nil {
				return err
			}
		}
	}
	return nil
}

// WriteArgs writes args
func (statement *Statement) WriteArgs(w *builder.BytesWriter, args []interface{}) error {
	for i, arg := range args {
		if err := statement.WriteArg(w, arg); err != nil {
			return err
		}

		if i+1 != len(args) {
			if _, err := w.WriteString(","); err != nil {
				return err
			}
		}
	}
	return nil
}