pool.go 9.28 KB
Newer Older
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package zdb

import (
	"context"
	"errors"
	"fmt"
	"github.com/jackc/pgx/v5/pgxpool"
	"log"
	"reflect"
	"strings"
	"sync"
	"sync/atomic"
	"time"
)

Vladimir Barsukov's avatar
Vladimir Barsukov committed
16
17
18
19
20
21
22
type Balance int

const (
	BalanceRoundRobin Balance = iota
	BalanceLeastConn
)

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
23
type Pool struct {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
24
25
26
27
28
29
30
	ctx             context.Context
	logger          Logger
	SrvMaster       *Conn
	SrvSync         []*Conn
	SrvAsync        []*Conn
	mu              *sync.RWMutex
	notAliveConns   []*Conn
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
31
32
	slavesIter      *atomic.Int64
	slavesAsyncIter *atomic.Int64
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
33
34
35
36
37
38
39
	stop            bool
	PgTsFormat      string
	Continues       []string
	ContinuesTry    []string
	TryOnError      int
	TryOnSleep      time.Duration
	Balance         Balance
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
40
	PingTimout      time.Duration
Vladimir Barsukov's avatar
Vladimir Barsukov committed
41
	PingTry         int
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
42
43
}

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
44
func New(ctx context.Context) *Pool {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
45
	return &Pool{
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
46
		ctx:             ctx,
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
47
48
49
		mu:              &sync.RWMutex{},
		slavesIter:      &atomic.Int64{},
		slavesAsyncIter: &atomic.Int64{},
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
50
		PgTsFormat:      "2006-01-02 15:04:05",
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
51
		Continues:       []string{"connect", "EOF", "conflict with recovery", "context deadline exceeded"},
Vladimir Barsukov's avatar
Vladimir Barsukov committed
52
53
		ContinuesTry:    []string{"conflict with recovery"},
		TryOnError:      1,
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
54
		TryOnSleep:      time.Second,
Vladimir Barsukov's avatar
Vladimir Barsukov committed
55
		Balance:         BalanceLeastConn,
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
56
		PingTimout:      time.Second * 5,
Vladimir Barsukov's avatar
Vladimir Barsukov committed
57
		PingTry:         5,
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
58
59
60
	}
}

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
61
func NewDefault() *Pool {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
62
	p := New(context.Background())
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
63
64
65
	p.logger = log.Default()

	return p
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
66
67
68
69
70
}

func (d *Pool) WithContext(ctx context.Context) *Pool {
	return &Pool{
		ctx:             ctx,
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
71
72
73
74
		logger:          d.logger,
		SrvMaster:       d.SrvMaster,
		SrvSync:         d.SrvSync,
		SrvAsync:        d.SrvAsync,
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
75
76
77
78
		mu:              d.mu,
		notAliveConns:   d.notAliveConns,
		slavesIter:      d.slavesIter,
		slavesAsyncIter: d.slavesAsyncIter,
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
79
80
81
82
83
84
85
		stop:            d.stop,
		PgTsFormat:      d.PgTsFormat,
		Continues:       d.Continues,
		ContinuesTry:    d.ContinuesTry,
		TryOnError:      d.TryOnError,
		TryOnSleep:      d.TryOnSleep,
		Balance:         d.Balance,
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
86
		PingTimout:      d.PingTimout,
Vladimir Barsukov's avatar
Vladimir Barsukov committed
87
		PingTry:         d.PingTry,
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
88
89
90
	}
}

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
91
func (d *Pool) WithTimeout(dur time.Duration) *Pool {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
92
	ctx, _ := context.WithTimeout(d.ctx, dur)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
93
94
95
96
97

	return d.WithContext(ctx)
}

func (d *Pool) WithDeadline(dur time.Time) *Pool {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
98
	ctx, _ := context.WithDeadline(d.ctx, dur)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
99
100
101
102

	return d.WithContext(ctx)
}

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
103
func (d *Pool) NewConn(mode connMode, pgConnString string) error {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
104
105
	d.mu.Lock()
	defer d.mu.Unlock()
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
106

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
107
108
109
110
	q, err := d.newConn(mode, pgConnString)

	switch mode {
	case ConnModeMaster:
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
111
		d.SrvMaster = q
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
112
	case ConnModeSync:
Vladimir Barsukov's avatar
Vladimir Barsukov committed
113
		q.Index = len(d.SrvSync)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
114
		d.SrvSync = append(d.SrvSync, q)
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
115
	case ConnModeAsync:
Vladimir Barsukov's avatar
Vladimir Barsukov committed
116
		q.Index = len(d.SrvAsync)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
117
		d.SrvAsync = append(d.SrvAsync, q)
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
118
119
	default:
		return errors.New("unknown mode")
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
120
	}
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
121
122

	return err
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
123
}
Vladimir Barsukov's avatar
Vladimir Barsukov committed
124
125
126
127
128
129
130
131
132
133
134

func (d *Pool) NewConns(mode connMode, pgConnString ...string) error {
	for _, s := range pgConnString {
		if err := d.NewConn(mode, s); err != nil {
			return err
		}
	}

	return nil
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
135
func (d *Pool) newConn(mode connMode, pgConnString string) (q *Conn, err error) {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
136
	var pgxPool *pgxpool.Pool
Vladimir Barsukov's avatar
Vladimir Barsukov committed
137
	var pgxConfig *pgxpool.Config
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
138
139
140
141
142

	if !strings.Contains(pgConnString, "default_query_exec_mode=") {
		pgConnString += " default_query_exec_mode=simple_protocol"
	}

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
143
144
145
146
	if !strings.Contains(pgConnString, "connect_timeout=") {
		pgConnString += " connect_timeout=3"
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
147
148
149
150
	if !strings.Contains(pgConnString, "sslmode=") {
		pgConnString += " sslmode=disable"
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
151
152
153
154
155
	if pgxConfig, err = pgxpool.ParseConfig(pgConnString); err != nil {
		return nil, err
	}

	if pgxPool, err = pgxpool.NewWithConfig(d.ctx, pgxConfig); err != nil {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
156
		return &Conn{Pool: pgxPool, Alive: false, Mode: mode}, err
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
157
158
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
159
	q = &Conn{Pool: pgxPool, Alive: false, Mode: mode}
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
160

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
161
	if err = d.Ping(q); err != nil {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
162
		return q, err
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
163
164
	}

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
165
	q.Alive = true
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
166

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
167
	return q, nil
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
168
169
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
func (d *Pool) least(s []*Conn) *Conn {
	var out *Conn
	var m float64 = 0

	for i, conn := range s {
		ratio := float64(conn.Stat().AcquiredConns()) / float64(conn.Stat().MaxConns())

		if ratio < m || i == 0 {
			m = ratio
			out = conn
		}
	}

	logConnStat(out)

	return out
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
188
func (d *Pool) sync() *Conn {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
189
190
	if len(d.SrvSync) == 0 {
		return d.SrvMaster
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
191
192
193
194
195
	}

	d.mu.RLock()
	defer d.mu.RUnlock()

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
196
197
	if len(d.SrvSync) == 1 {
		return d.SrvSync[0]
Vladimir Barsukov's avatar
Vladimir Barsukov committed
198
199
200
	}

	if d.Balance == BalanceRoundRobin {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
201
		return d.SrvSync[d.slavesIter.Add(1)%int64(len(d.SrvSync))]
Vladimir Barsukov's avatar
Vladimir Barsukov committed
202
203
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
204
	return d.least(d.SrvSync)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
205
206
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
207
func (d *Pool) async() *Conn {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
208
	if len(d.SrvAsync) == 0 {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
209
		return d.sync()
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
210
211
212
213
214
	}

	d.mu.RLock()
	defer d.mu.RUnlock()

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
215
216
	if len(d.SrvAsync) == 1 {
		return d.SrvAsync[0]
Vladimir Barsukov's avatar
Vladimir Barsukov committed
217
218
219
	}

	if d.Balance == BalanceRoundRobin {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
220
		return d.SrvAsync[d.slavesAsyncIter.Add(1)%int64(len(d.SrvAsync))]
Vladimir Barsukov's avatar
Vladimir Barsukov committed
221
222
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
223
	return d.least(d.SrvAsync)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
224
225
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
226
func (d *Pool) execWrapper(pool connMode, dst any, f func(conn *Conn, dst1 any) error) error {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
227
	for {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
228
		var q *Conn
Vladimir Barsukov's avatar
Vladimir Barsukov committed
229
		try := 0
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
230
231

		if pool == ConnModeSync {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
232
			q = d.sync()
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
233
		} else {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
234
			q = d.async()
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
235
236
		}

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
237
	repeat:
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
238
239
		if err := f(q, dst); err != nil {
			if q.Mode == ConnModeMaster {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
240
241
				return err
			} else {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
242
243
244

				if try < d.TryOnError && contains(err.Error(), d.ContinuesTry) {
					try++
Vladimir Barsukov's avatar
Vladimir Barsukov committed
245
					d.logger.Printf("ZDB_EXEC_WRAPPER_REPEAT_ERR: SRV: %s TRY: %d; %s", q.ToString(), try, err.Error())
Vladimir Barsukov's avatar
Vladimir Barsukov committed
246
247

					time.Sleep(d.TryOnSleep)
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
248
					goto repeat
Vladimir Barsukov's avatar
Vladimir Barsukov committed
249
250
251
				}

				if contains(err.Error(), d.Continues) {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
252
					d.setNotAliveConn(q)
Vladimir Barsukov's avatar
Vladimir Barsukov committed
253
					d.logger.Printf("ZDB_EXEC_WRAPPER_ERR: SRV: %s; %s", q.ToString(), err.Error())
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
254
255
256
257
258
259
260
261
262
263
264
					continue
				} else {
					return err
				}
			}
		}

		return nil
	}
}

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
265
func (d *Pool) Ping(q *Conn) (err error) {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
266
267
	var n any

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
268
	if err = d.WithTimeout(d.PingTimout).qGet(q, &n, "SELECT 1"); err != nil {
Vladimir Barsukov's avatar
Vladimir Barsukov committed
269
270
271
		q.PingTry++

		d.logger.Printf("ZDB_PING_ERR: SRV: %s; TRY: %d; %v",
Vladimir Barsukov's avatar
Vladimir Barsukov committed
272
			q.ToString(),
Vladimir Barsukov's avatar
Vladimir Barsukov committed
273
			q.PingTry,
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
274
275
			err,
		)
Vladimir Barsukov's avatar
Vladimir Barsukov committed
276
277
278
279

		if d.PingTry <= q.PingTry {
			return nil
		}
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
280
281
	}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
282
283
	q.PingTry = 0

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
284
285
286
	return
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
287
func (d *Pool) setNotAliveConn(conn *Conn) {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
288
289
290
	d.mu.Lock()
	defer d.mu.Unlock()

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
291
	for i, slave := range d.SrvSync {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
292
293
294
		if slave == conn {
			conn.Alive = false
			d.notAliveConns = append(d.notAliveConns, conn)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
295
			d.SrvSync = remove(d.SrvSync, i)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
296
297
298
299
			return
		}
	}

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
300
	for i, slave := range d.SrvAsync {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
301
302
303
		if slave == conn {
			conn.Alive = false
			d.notAliveConns = append(d.notAliveConns, conn)
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
304
			d.SrvAsync = remove(d.SrvAsync, i)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
305
306
307
308
309
310

			return
		}
	}
}

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
311
312
313
func (d *Pool) Start() {
	d.stop = false

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
314
315
	go func() {
		for {
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
316
317
318
319
			if d.stop {
				return
			}

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
320
		rep:
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
321
			for i, q := range d.notAliveConns {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
322
				if err := d.Ping(q); err == nil {
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
323
					d.mu.Lock()
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
324
					q.Alive = true
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
325
					d.notAliveConns = remove(d.notAliveConns, i)
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
326
					if q.Mode == ConnModeSync {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
327
						d.SrvSync = append(d.SrvSync, q)
Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
328
					} else if q.Mode == ConnModeAsync {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
329
						d.SrvAsync = append(d.SrvAsync, q)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
330
331
					}
					d.mu.Unlock()
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
332
					goto rep
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
333
334
335
				}
			}

Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
336
			if d.SrvMaster != nil {
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
337
				d.SrvMaster.Alive = d.Ping(d.SrvMaster) == nil
Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
338
			}
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
339

Vladimir Barsukov's avatar
fix    
Vladimir Barsukov committed
340
			time.Sleep(time.Second)
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
341
342
343
344
		}
	}()
}

Vladimir Barsukov's avatar
save    
Vladimir Barsukov committed
345
346
347
348
func (d *Pool) Stop() {
	d.stop = true
}

Vladimir Barsukov's avatar
Vladimir Barsukov committed
349
func (d *Pool) IsAlive() bool {
Vladimir Barsukov's avatar
timeout    
Vladimir Barsukov committed
350
	return d.SrvMaster != nil && d.SrvMaster.Alive
Vladimir Barsukov's avatar
Vladimir Barsukov committed
351
352
}

Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
func (d *Pool) prepare(sql string, param map[string]any) string {
	for n, t := range param {
		switch t.(type) {
		case time.Time:
			sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("'%s'", t.(time.Time).UTC().Format(time.DateTime)))
		case *time.Time:
			if t.(*time.Time) == nil {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("'%s'", t.(*time.Time).UTC().Format(time.DateTime)))
			}
		case nil:
			sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
		case bool:
			if t.(bool) {
				sql = strings.ReplaceAll(sql, ":"+n+":", "TRUE")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", "FALSE")
			}
		case *string:
			if t.(*string) == nil || *t.(*string) == "NULL" {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("'%v'", strings.ReplaceAll(*t.(*string), "'", "''")))
			}
		case string:
			if t.(string) == "NULL" {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("'%v'", strings.ReplaceAll(t.(string), "'", "''")))
			}
		case *int:
			if t.(*int) == nil {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("%v", *t.(*int)))
			}
		case *bool:
			if t.(*bool) == nil {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				if *t.(*bool) {
					sql = strings.ReplaceAll(sql, ":"+n+":", "TRUE")
				} else {
					sql = strings.ReplaceAll(sql, ":"+n+":", "FALSE")
				}
			}
		case *int64:
			if t.(*int64) == nil {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("%v", *t.(*int64)))
			}
		case *float64:
			if t.(*float64) == nil {
				sql = strings.ReplaceAll(sql, ":"+n+":", "NULL")
			} else {
				sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("%v", *t.(*float64)))
			}
		case int, int64:
			sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("%v", t))
		default:
			switch reflect.TypeOf(t).Kind() {
			case reflect.Slice:
				sql = strings.ReplaceAll(sql, ":"+n+":", "'{"+strings.Trim(strings.Join(strings.Split(fmt.Sprint(t), " "), ","), "[]")+"}'")
			}

			sql = strings.ReplaceAll(sql, ":"+n+":", fmt.Sprintf("'%v'", t))
		}
	}

Vladimir Barsukov's avatar
log    
Vladimir Barsukov committed
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
	if v, ok := param["_debug"]; ok {
		switch vv := v.(type) {
		case bool:
			if vv {
				d.logger.Printf(sql)
			}
		case int, uint:
			if vv == 1 {
				d.logger.Printf(sql)
			}
		case string:
			if vv == "1" {
				d.logger.Printf(sql)
			}
		}
Vladimir Barsukov's avatar
init  
Vladimir Barsukov committed
439
440
441
442
	}

	return sql
}