dialect.go (3526B)
1 package schema 2 3 import ( 4 "database/sql" 5 "encoding/hex" 6 "strconv" 7 "time" 8 "unicode/utf8" 9 10 "github.com/uptrace/bun/dialect" 11 "github.com/uptrace/bun/dialect/feature" 12 "github.com/uptrace/bun/internal/parser" 13 ) 14 15 type Dialect interface { 16 Init(db *sql.DB) 17 18 Name() dialect.Name 19 Features() feature.Feature 20 21 Tables() *Tables 22 OnTable(table *Table) 23 24 IdentQuote() byte 25 26 AppendUint32(b []byte, n uint32) []byte 27 AppendUint64(b []byte, n uint64) []byte 28 AppendTime(b []byte, tm time.Time) []byte 29 AppendString(b []byte, s string) []byte 30 AppendBytes(b []byte, bs []byte) []byte 31 AppendJSON(b, jsonb []byte) []byte 32 AppendBool(b []byte, v bool) []byte 33 34 // DefaultVarcharLen should be returned for dialects in which specifying VARCHAR length 35 // is mandatory in queries that modify the schema (CREATE TABLE / ADD COLUMN, etc). 36 // Dialects that do not have such requirement may return 0, which should be interpreted so by the caller. 37 DefaultVarcharLen() int 38 } 39 40 // ------------------------------------------------------------------------------ 41 42 type BaseDialect struct{} 43 44 func (BaseDialect) AppendUint32(b []byte, n uint32) []byte { 45 return strconv.AppendUint(b, uint64(n), 10) 46 } 47 48 func (BaseDialect) AppendUint64(b []byte, n uint64) []byte { 49 return strconv.AppendUint(b, n, 10) 50 } 51 52 func (BaseDialect) AppendTime(b []byte, tm time.Time) []byte { 53 b = append(b, '\'') 54 b = tm.UTC().AppendFormat(b, "2006-01-02 15:04:05.999999-07:00") 55 b = append(b, '\'') 56 return b 57 } 58 59 func (BaseDialect) AppendString(b []byte, s string) []byte { 60 b = append(b, '\'') 61 for _, r := range s { 62 if r == '\000' { 63 continue 64 } 65 66 if r == '\'' { 67 b = append(b, '\'', '\'') 68 continue 69 } 70 71 if r < utf8.RuneSelf { 72 b = append(b, byte(r)) 73 continue 74 } 75 76 l := len(b) 77 if cap(b)-l < utf8.UTFMax { 78 b = append(b, make([]byte, utf8.UTFMax)...) 79 } 80 n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r) 81 b = b[:l+n] 82 } 83 b = append(b, '\'') 84 return b 85 } 86 87 func (BaseDialect) AppendBytes(b, bs []byte) []byte { 88 if bs == nil { 89 return dialect.AppendNull(b) 90 } 91 92 b = append(b, `'\x`...) 93 94 s := len(b) 95 b = append(b, make([]byte, hex.EncodedLen(len(bs)))...) 96 hex.Encode(b[s:], bs) 97 98 b = append(b, '\'') 99 100 return b 101 } 102 103 func (BaseDialect) AppendJSON(b, jsonb []byte) []byte { 104 b = append(b, '\'') 105 106 p := parser.New(jsonb) 107 for p.Valid() { 108 c := p.Read() 109 switch c { 110 case '"': 111 b = append(b, '"') 112 case '\'': 113 b = append(b, "''"...) 114 case '\000': 115 continue 116 case '\\': 117 if p.SkipBytes([]byte("u0000")) { 118 b = append(b, `\\u0000`...) 119 } else { 120 b = append(b, '\\') 121 if p.Valid() { 122 b = append(b, p.Read()) 123 } 124 } 125 default: 126 b = append(b, c) 127 } 128 } 129 130 b = append(b, '\'') 131 132 return b 133 } 134 135 func (BaseDialect) AppendBool(b []byte, v bool) []byte { 136 return dialect.AppendBool(b, v) 137 } 138 139 // ------------------------------------------------------------------------------ 140 141 type nopDialect struct { 142 BaseDialect 143 144 tables *Tables 145 features feature.Feature 146 } 147 148 func newNopDialect() *nopDialect { 149 d := new(nopDialect) 150 d.tables = NewTables(d) 151 d.features = feature.Returning 152 return d 153 } 154 155 func (d *nopDialect) Init(*sql.DB) {} 156 157 func (d *nopDialect) Name() dialect.Name { 158 return dialect.Invalid 159 } 160 161 func (d *nopDialect) Features() feature.Feature { 162 return d.features 163 } 164 165 func (d *nopDialect) Tables() *Tables { 166 return d.tables 167 } 168 169 func (d *nopDialect) OnField(field *Field) {} 170 171 func (d *nopDialect) OnTable(table *Table) {} 172 173 func (d *nopDialect) IdentQuote() byte { 174 return '"' 175 } 176 177 func (d *nopDialect) DefaultVarcharLen() int { 178 return 0 179 }