github.com/wangyougui/gf/v2@v2.6.5/database/gdb/gdb_core_utility.go (about) 1 // Copyright GoFrame Author(https://goframe.org). All Rights Reserved. 2 // 3 // This Source Code Form is subject to the terms of the MIT License. 4 // If a copy of the MIT was not distributed with this file, 5 // You can obtain one at https://github.com/wangyougui/gf. 6 // 7 8 package gdb 9 10 import ( 11 "context" 12 "fmt" 13 14 "github.com/wangyougui/gf/v2/crypto/gmd5" 15 "github.com/wangyougui/gf/v2/errors/gcode" 16 "github.com/wangyougui/gf/v2/errors/gerror" 17 "github.com/wangyougui/gf/v2/text/gregex" 18 "github.com/wangyougui/gf/v2/text/gstr" 19 "github.com/wangyougui/gf/v2/util/gconv" 20 "github.com/wangyougui/gf/v2/util/gutil" 21 ) 22 23 // GetDB returns the underlying DB. 24 func (c *Core) GetDB() DB { 25 return c.db 26 } 27 28 // GetLink creates and returns the underlying database link object with transaction checks. 29 // The parameter `master` specifies whether using the master node if master-slave configured. 30 func (c *Core) GetLink(ctx context.Context, master bool, schema string) (Link, error) { 31 tx := TXFromCtx(ctx, c.db.GetGroup()) 32 if tx != nil { 33 return &txLink{tx.GetSqlTX()}, nil 34 } 35 if master { 36 link, err := c.db.GetCore().MasterLink(schema) 37 if err != nil { 38 return nil, err 39 } 40 return link, nil 41 } 42 link, err := c.db.GetCore().SlaveLink(schema) 43 if err != nil { 44 return nil, err 45 } 46 return link, nil 47 } 48 49 // MasterLink acts like function Master but with additional `schema` parameter specifying 50 // the schema for the connection. It is defined for internal usage. 51 // Also see Master. 52 func (c *Core) MasterLink(schema ...string) (Link, error) { 53 db, err := c.db.Master(schema...) 54 if err != nil { 55 return nil, err 56 } 57 return &dbLink{ 58 DB: db, 59 isOnMaster: true, 60 }, nil 61 } 62 63 // SlaveLink acts like function Slave but with additional `schema` parameter specifying 64 // the schema for the connection. It is defined for internal usage. 65 // Also see Slave. 66 func (c *Core) SlaveLink(schema ...string) (Link, error) { 67 db, err := c.db.Slave(schema...) 68 if err != nil { 69 return nil, err 70 } 71 return &dbLink{ 72 DB: db, 73 isOnMaster: false, 74 }, nil 75 } 76 77 // QuoteWord checks given string `s` a word, 78 // if true it quotes `s` with security chars of the database 79 // and returns the quoted string; or else it returns `s` without any change. 80 // 81 // The meaning of a `word` can be considered as a column name. 82 func (c *Core) QuoteWord(s string) string { 83 s = gstr.Trim(s) 84 if s == "" { 85 return s 86 } 87 charLeft, charRight := c.db.GetChars() 88 return doQuoteWord(s, charLeft, charRight) 89 } 90 91 // QuoteString quotes string with quote chars. Strings like: 92 // "user", "user u", "user,user_detail", "user u, user_detail ut", "u.id asc". 93 // 94 // The meaning of a `string` can be considered as part of a statement string including columns. 95 func (c *Core) QuoteString(s string) string { 96 if !gregex.IsMatchString(regularFieldNameWithCommaRegPattern, s) { 97 return s 98 } 99 charLeft, charRight := c.db.GetChars() 100 return doQuoteString(s, charLeft, charRight) 101 } 102 103 // QuotePrefixTableName adds prefix string and quotes chars for the table. 104 // It handles table string like: 105 // "user", "user u", 106 // "user,user_detail", 107 // "user u, user_detail ut", 108 // "user as u, user_detail as ut". 109 // 110 // Note that, this will automatically checks the table prefix whether already added, 111 // if true it does nothing to the table name, or else adds the prefix to the table name. 112 func (c *Core) QuotePrefixTableName(table string) string { 113 charLeft, charRight := c.db.GetChars() 114 return doQuoteTableName(table, c.db.GetPrefix(), charLeft, charRight) 115 } 116 117 // GetChars returns the security char for current database. 118 // It does nothing in default. 119 func (c *Core) GetChars() (charLeft string, charRight string) { 120 return "", "" 121 } 122 123 // Tables retrieves and returns the tables of current schema. 124 // It's mainly used in cli tool chain for automatically generating the models. 125 func (c *Core) Tables(ctx context.Context, schema ...string) (tables []string, err error) { 126 return 127 } 128 129 // TableFields retrieves and returns the fields' information of specified table of current 130 // schema. 131 // 132 // The parameter `link` is optional, if given nil it automatically retrieves a raw sql connection 133 // as its link to proceed necessary sql query. 134 // 135 // Note that it returns a map containing the field name and its corresponding fields. 136 // As a map is unsorted, the TableField struct has an "Index" field marks its sequence in 137 // the fields. 138 // 139 // It's using cache feature to enhance the performance, which is never expired util the 140 // process restarts. 141 func (c *Core) TableFields(ctx context.Context, table string, schema ...string) (fields map[string]*TableField, err error) { 142 return 143 } 144 145 // ClearTableFields removes certain cached table fields of current configuration group. 146 func (c *Core) ClearTableFields(ctx context.Context, table string, schema ...string) (err error) { 147 tableFieldsMap.Remove(fmt.Sprintf( 148 `%s%s@%s#%s`, 149 cachePrefixTableFields, 150 c.db.GetGroup(), 151 gutil.GetOrDefaultStr(c.db.GetSchema(), schema...), 152 table, 153 )) 154 return 155 } 156 157 // ClearTableFieldsAll removes all cached table fields of current configuration group. 158 func (c *Core) ClearTableFieldsAll(ctx context.Context) (err error) { 159 var ( 160 keys = tableFieldsMap.Keys() 161 cachePrefix = fmt.Sprintf(`%s%s`, cachePrefixTableFields, c.db.GetGroup()) 162 removedKeys = make([]string, 0) 163 ) 164 for _, key := range keys { 165 if gstr.HasPrefix(key, cachePrefix) { 166 removedKeys = append(removedKeys, key) 167 } 168 } 169 if len(removedKeys) > 0 { 170 tableFieldsMap.Removes(removedKeys) 171 } 172 return 173 } 174 175 // ClearCache removes cached sql result of certain table. 176 func (c *Core) ClearCache(ctx context.Context, table string) (err error) { 177 return c.db.GetCache().Clear(ctx) 178 } 179 180 // ClearCacheAll removes all cached sql result from cache 181 func (c *Core) ClearCacheAll(ctx context.Context) (err error) { 182 return c.db.GetCache().Clear(ctx) 183 } 184 185 func (c *Core) makeSelectCacheKey(name, schema, table, sql string, args ...interface{}) string { 186 if name == "" { 187 name = fmt.Sprintf( 188 `%s@%s#%s:%s`, 189 c.db.GetGroup(), 190 schema, 191 table, 192 gmd5.MustEncryptString(sql+", @PARAMS:"+gconv.String(args)), 193 ) 194 } 195 return fmt.Sprintf(`%s%s`, cachePrefixSelectCache, name) 196 } 197 198 // HasField determine whether the field exists in the table. 199 func (c *Core) HasField(ctx context.Context, table, field string, schema ...string) (bool, error) { 200 table = c.guessPrimaryTableName(table) 201 tableFields, err := c.db.TableFields(ctx, table, schema...) 202 if err != nil { 203 return false, err 204 } 205 if len(tableFields) == 0 { 206 return false, gerror.NewCodef( 207 gcode.CodeNotFound, 208 `empty table fields for table "%s"`, table, 209 ) 210 } 211 fieldsArray := make([]string, len(tableFields)) 212 for k, v := range tableFields { 213 fieldsArray[v.Index] = k 214 } 215 charLeft, charRight := c.db.GetChars() 216 field = gstr.Trim(field, charLeft+charRight) 217 for _, f := range fieldsArray { 218 if f == field { 219 return true, nil 220 } 221 } 222 return false, nil 223 } 224 225 // guessPrimaryTableName parses and returns the primary table name. 226 func (c *Core) guessPrimaryTableName(tableStr string) string { 227 if tableStr == "" { 228 return "" 229 } 230 var ( 231 guessedTableName string 232 array1 = gstr.SplitAndTrim(tableStr, ",") 233 array2 = gstr.SplitAndTrim(array1[0], " ") 234 array3 = gstr.SplitAndTrim(array2[0], ".") 235 ) 236 if len(array3) >= 2 { 237 guessedTableName = array3[1] 238 } else { 239 guessedTableName = array3[0] 240 } 241 charL, charR := c.db.GetChars() 242 if charL != "" || charR != "" { 243 guessedTableName = gstr.Trim(guessedTableName, charL+charR) 244 } 245 if !gregex.IsMatchString(regularFieldNameRegPattern, guessedTableName) { 246 return "" 247 } 248 return guessedTableName 249 }