2021-08-25 16:34:33 +03:00
|
|
|
package schema
|
|
|
|
|
|
|
|
import (
|
|
|
|
"database/sql"
|
2021-11-13 14:29:08 +03:00
|
|
|
"encoding/hex"
|
2021-10-24 14:14:37 +03:00
|
|
|
"strconv"
|
|
|
|
"time"
|
2021-11-13 14:29:08 +03:00
|
|
|
"unicode/utf8"
|
2021-08-25 16:34:33 +03:00
|
|
|
|
|
|
|
"github.com/uptrace/bun/dialect"
|
|
|
|
"github.com/uptrace/bun/dialect/feature"
|
2021-10-24 14:14:37 +03:00
|
|
|
"github.com/uptrace/bun/internal/parser"
|
2021-08-25 16:34:33 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
type Dialect interface {
|
|
|
|
Init(db *sql.DB)
|
|
|
|
|
|
|
|
Name() dialect.Name
|
|
|
|
Features() feature.Feature
|
|
|
|
|
|
|
|
Tables() *Tables
|
|
|
|
OnTable(table *Table)
|
|
|
|
|
|
|
|
IdentQuote() byte
|
2021-10-24 14:14:37 +03:00
|
|
|
|
|
|
|
AppendUint32(b []byte, n uint32) []byte
|
|
|
|
AppendUint64(b []byte, n uint64) []byte
|
|
|
|
AppendTime(b []byte, tm time.Time) []byte
|
2021-11-13 14:29:08 +03:00
|
|
|
AppendString(b []byte, s string) []byte
|
2021-10-24 14:14:37 +03:00
|
|
|
AppendBytes(b []byte, bs []byte) []byte
|
|
|
|
AppendJSON(b, jsonb []byte) []byte
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type BaseDialect struct{}
|
|
|
|
|
|
|
|
func (BaseDialect) AppendUint32(b []byte, n uint32) []byte {
|
|
|
|
return strconv.AppendUint(b, uint64(n), 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (BaseDialect) AppendUint64(b []byte, n uint64) []byte {
|
|
|
|
return strconv.AppendUint(b, n, 10)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (BaseDialect) AppendTime(b []byte, tm time.Time) []byte {
|
|
|
|
b = append(b, '\'')
|
|
|
|
b = tm.UTC().AppendFormat(b, "2006-01-02 15:04:05.999999-07:00")
|
|
|
|
b = append(b, '\'')
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2021-11-13 14:29:08 +03:00
|
|
|
func (BaseDialect) AppendString(b []byte, s string) []byte {
|
|
|
|
b = append(b, '\'')
|
|
|
|
for _, r := range s {
|
|
|
|
if r == '\000' {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if r == '\'' {
|
|
|
|
b = append(b, '\'', '\'')
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if r < utf8.RuneSelf {
|
|
|
|
b = append(b, byte(r))
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
l := len(b)
|
|
|
|
if cap(b)-l < utf8.UTFMax {
|
|
|
|
b = append(b, make([]byte, utf8.UTFMax)...)
|
|
|
|
}
|
|
|
|
n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r)
|
|
|
|
b = b[:l+n]
|
|
|
|
}
|
|
|
|
b = append(b, '\'')
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
|
2021-10-24 14:14:37 +03:00
|
|
|
func (BaseDialect) AppendBytes(b, bs []byte) []byte {
|
2021-11-13 14:29:08 +03:00
|
|
|
if bs == nil {
|
|
|
|
return dialect.AppendNull(b)
|
|
|
|
}
|
|
|
|
|
|
|
|
b = append(b, `'\x`...)
|
|
|
|
|
|
|
|
s := len(b)
|
|
|
|
b = append(b, make([]byte, hex.EncodedLen(len(bs)))...)
|
|
|
|
hex.Encode(b[s:], bs)
|
|
|
|
|
|
|
|
b = append(b, '\'')
|
|
|
|
|
|
|
|
return b
|
2021-10-24 14:14:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
func (BaseDialect) AppendJSON(b, jsonb []byte) []byte {
|
|
|
|
b = append(b, '\'')
|
|
|
|
|
|
|
|
p := parser.New(jsonb)
|
|
|
|
for p.Valid() {
|
|
|
|
c := p.Read()
|
|
|
|
switch c {
|
|
|
|
case '"':
|
|
|
|
b = append(b, '"')
|
|
|
|
case '\'':
|
|
|
|
b = append(b, "''"...)
|
|
|
|
case '\000':
|
|
|
|
continue
|
|
|
|
case '\\':
|
|
|
|
if p.SkipBytes([]byte("u0000")) {
|
|
|
|
b = append(b, `\\u0000`...)
|
|
|
|
} else {
|
|
|
|
b = append(b, '\\')
|
|
|
|
if p.Valid() {
|
|
|
|
b = append(b, p.Read())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
b = append(b, c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
b = append(b, '\'')
|
|
|
|
|
|
|
|
return b
|
2021-08-25 16:34:33 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
type nopDialect struct {
|
2021-10-24 14:14:37 +03:00
|
|
|
BaseDialect
|
|
|
|
|
2021-08-25 16:34:33 +03:00
|
|
|
tables *Tables
|
|
|
|
features feature.Feature
|
|
|
|
}
|
|
|
|
|
|
|
|
func newNopDialect() *nopDialect {
|
|
|
|
d := new(nopDialect)
|
|
|
|
d.tables = NewTables(d)
|
|
|
|
d.features = feature.Returning
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *nopDialect) Init(*sql.DB) {}
|
|
|
|
|
|
|
|
func (d *nopDialect) Name() dialect.Name {
|
|
|
|
return dialect.Invalid
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *nopDialect) Features() feature.Feature {
|
|
|
|
return d.features
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *nopDialect) Tables() *Tables {
|
|
|
|
return d.tables
|
|
|
|
}
|
|
|
|
|
|
|
|
func (d *nopDialect) OnField(field *Field) {}
|
|
|
|
|
|
|
|
func (d *nopDialect) OnTable(table *Table) {}
|
|
|
|
|
|
|
|
func (d *nopDialect) IdentQuote() byte {
|
|
|
|
return '"'
|
|
|
|
}
|