finisher_api.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
  1. package gorm
  2. import (
  3. "database/sql"
  4. "errors"
  5. "fmt"
  6. "reflect"
  7. "strings"
  8. "gorm.io/gorm/clause"
  9. "gorm.io/gorm/logger"
  10. "gorm.io/gorm/schema"
  11. "gorm.io/gorm/utils"
  12. )
  13. // Create insert the value into database
  14. func (db *DB) Create(value interface{}) (tx *DB) {
  15. if db.CreateBatchSize > 0 {
  16. return db.CreateInBatches(value, db.CreateBatchSize)
  17. }
  18. tx = db.getInstance()
  19. tx.Statement.Dest = value
  20. tx.callbacks.Create().Execute(tx)
  21. return
  22. }
  23. // CreateInBatches insert the value in batches into database
  24. func (db *DB) CreateInBatches(value interface{}, batchSize int) (tx *DB) {
  25. reflectValue := reflect.Indirect(reflect.ValueOf(value))
  26. switch reflectValue.Kind() {
  27. case reflect.Slice, reflect.Array:
  28. var rowsAffected int64
  29. tx = db.getInstance()
  30. callFc := func(tx *DB) error {
  31. for i := 0; i < reflectValue.Len(); i += batchSize {
  32. ends := i + batchSize
  33. if ends > reflectValue.Len() {
  34. ends = reflectValue.Len()
  35. }
  36. subtx := tx.getInstance()
  37. subtx.Statement.Dest = reflectValue.Slice(i, ends).Interface()
  38. subtx.callbacks.Create().Execute(subtx)
  39. if subtx.Error != nil {
  40. return subtx.Error
  41. }
  42. rowsAffected += subtx.RowsAffected
  43. }
  44. return nil
  45. }
  46. if tx.SkipDefaultTransaction {
  47. tx.AddError(callFc(tx.Session(&Session{})))
  48. } else {
  49. tx.AddError(tx.Transaction(callFc))
  50. }
  51. tx.RowsAffected = rowsAffected
  52. default:
  53. tx = db.getInstance()
  54. tx.Statement.Dest = value
  55. tx.callbacks.Create().Execute(tx)
  56. }
  57. return
  58. }
  59. // Save update value in database, if the value doesn't have primary key, will insert it
  60. func (db *DB) Save(value interface{}) (tx *DB) {
  61. tx = db.getInstance()
  62. tx.Statement.Dest = value
  63. reflectValue := reflect.Indirect(reflect.ValueOf(value))
  64. switch reflectValue.Kind() {
  65. case reflect.Slice, reflect.Array:
  66. if _, ok := tx.Statement.Clauses["ON CONFLICT"]; !ok {
  67. tx = tx.Clauses(clause.OnConflict{UpdateAll: true})
  68. }
  69. tx.callbacks.Create().Execute(tx.InstanceSet("gorm:update_track_time", true))
  70. case reflect.Struct:
  71. if err := tx.Statement.Parse(value); err == nil && tx.Statement.Schema != nil {
  72. for _, pf := range tx.Statement.Schema.PrimaryFields {
  73. if _, isZero := pf.ValueOf(reflectValue); isZero {
  74. tx.callbacks.Create().Execute(tx)
  75. return
  76. }
  77. }
  78. }
  79. fallthrough
  80. default:
  81. selectedUpdate := len(tx.Statement.Selects) != 0
  82. // when updating, use all fields including those zero-value fields
  83. if !selectedUpdate {
  84. tx.Statement.Selects = append(tx.Statement.Selects, "*")
  85. }
  86. tx.callbacks.Update().Execute(tx)
  87. if tx.Error == nil && tx.RowsAffected == 0 && !tx.DryRun && !selectedUpdate {
  88. result := reflect.New(tx.Statement.Schema.ModelType).Interface()
  89. if err := tx.Session(&Session{}).First(result).Error; errors.Is(err, ErrRecordNotFound) {
  90. return tx.Create(value)
  91. }
  92. }
  93. }
  94. return
  95. }
  96. // First find first record that match given conditions, order by primary key
  97. func (db *DB) First(dest interface{}, conds ...interface{}) (tx *DB) {
  98. tx = db.Limit(1).Order(clause.OrderByColumn{
  99. Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
  100. })
  101. if len(conds) > 0 {
  102. if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
  103. tx.Statement.AddClause(clause.Where{Exprs: exprs})
  104. }
  105. }
  106. tx.Statement.RaiseErrorOnNotFound = true
  107. tx.Statement.Dest = dest
  108. tx.callbacks.Query().Execute(tx)
  109. return
  110. }
  111. // Take return a record that match given conditions, the order will depend on the database implementation
  112. func (db *DB) Take(dest interface{}, conds ...interface{}) (tx *DB) {
  113. tx = db.Limit(1)
  114. if len(conds) > 0 {
  115. if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
  116. tx.Statement.AddClause(clause.Where{Exprs: exprs})
  117. }
  118. }
  119. tx.Statement.RaiseErrorOnNotFound = true
  120. tx.Statement.Dest = dest
  121. tx.callbacks.Query().Execute(tx)
  122. return
  123. }
  124. // Last find last record that match given conditions, order by primary key
  125. func (db *DB) Last(dest interface{}, conds ...interface{}) (tx *DB) {
  126. tx = db.Limit(1).Order(clause.OrderByColumn{
  127. Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
  128. Desc: true,
  129. })
  130. if len(conds) > 0 {
  131. if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
  132. tx.Statement.AddClause(clause.Where{Exprs: exprs})
  133. }
  134. }
  135. tx.Statement.RaiseErrorOnNotFound = true
  136. tx.Statement.Dest = dest
  137. tx.callbacks.Query().Execute(tx)
  138. return
  139. }
  140. // Find find records that match given conditions
  141. func (db *DB) Find(dest interface{}, conds ...interface{}) (tx *DB) {
  142. tx = db.getInstance()
  143. if len(conds) > 0 {
  144. if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
  145. tx.Statement.AddClause(clause.Where{Exprs: exprs})
  146. }
  147. }
  148. tx.Statement.Dest = dest
  149. tx.callbacks.Query().Execute(tx)
  150. return
  151. }
  152. // FindInBatches find records in batches
  153. func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB {
  154. var (
  155. tx = db.Order(clause.OrderByColumn{
  156. Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
  157. }).Session(&Session{})
  158. queryDB = tx
  159. rowsAffected int64
  160. batch int
  161. )
  162. for {
  163. result := queryDB.Limit(batchSize).Find(dest)
  164. rowsAffected += result.RowsAffected
  165. batch++
  166. if result.Error == nil && result.RowsAffected != 0 {
  167. tx.AddError(fc(result, batch))
  168. }
  169. if tx.Error != nil || int(result.RowsAffected) < batchSize {
  170. break
  171. } else {
  172. resultsValue := reflect.Indirect(reflect.ValueOf(dest))
  173. if result.Statement.Schema.PrioritizedPrimaryField == nil {
  174. tx.AddError(ErrPrimaryKeyRequired)
  175. break
  176. } else {
  177. primaryValue, _ := result.Statement.Schema.PrioritizedPrimaryField.ValueOf(resultsValue.Index(resultsValue.Len() - 1))
  178. queryDB = tx.Clauses(clause.Gt{Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey}, Value: primaryValue})
  179. }
  180. }
  181. }
  182. tx.RowsAffected = rowsAffected
  183. return tx
  184. }
  185. func (tx *DB) assignInterfacesToValue(values ...interface{}) {
  186. for _, value := range values {
  187. switch v := value.(type) {
  188. case []clause.Expression:
  189. for _, expr := range v {
  190. if eq, ok := expr.(clause.Eq); ok {
  191. switch column := eq.Column.(type) {
  192. case string:
  193. if field := tx.Statement.Schema.LookUpField(column); field != nil {
  194. tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
  195. }
  196. case clause.Column:
  197. if field := tx.Statement.Schema.LookUpField(column.Name); field != nil {
  198. tx.AddError(field.Set(tx.Statement.ReflectValue, eq.Value))
  199. }
  200. }
  201. } else if andCond, ok := expr.(clause.AndConditions); ok {
  202. tx.assignInterfacesToValue(andCond.Exprs)
  203. }
  204. }
  205. case clause.Expression, map[string]string, map[interface{}]interface{}, map[string]interface{}:
  206. if exprs := tx.Statement.BuildCondition(value); len(exprs) > 0 {
  207. tx.assignInterfacesToValue(exprs)
  208. }
  209. default:
  210. if s, err := schema.Parse(value, tx.cacheStore, tx.NamingStrategy); err == nil {
  211. reflectValue := reflect.Indirect(reflect.ValueOf(value))
  212. switch reflectValue.Kind() {
  213. case reflect.Struct:
  214. for _, f := range s.Fields {
  215. if f.Readable {
  216. if v, isZero := f.ValueOf(reflectValue); !isZero {
  217. if field := tx.Statement.Schema.LookUpField(f.Name); field != nil {
  218. tx.AddError(field.Set(tx.Statement.ReflectValue, v))
  219. }
  220. }
  221. }
  222. }
  223. }
  224. } else if len(values) > 0 {
  225. if exprs := tx.Statement.BuildCondition(values[0], values[1:]...); len(exprs) > 0 {
  226. tx.assignInterfacesToValue(exprs)
  227. }
  228. return
  229. }
  230. }
  231. }
  232. }
  233. func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) (tx *DB) {
  234. queryTx := db.Limit(1).Order(clause.OrderByColumn{
  235. Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
  236. })
  237. if tx = queryTx.Find(dest, conds...); queryTx.RowsAffected == 0 {
  238. if c, ok := tx.Statement.Clauses["WHERE"]; ok {
  239. if where, ok := c.Expression.(clause.Where); ok {
  240. tx.assignInterfacesToValue(where.Exprs)
  241. }
  242. }
  243. // initialize with attrs, conds
  244. if len(tx.Statement.attrs) > 0 {
  245. tx.assignInterfacesToValue(tx.Statement.attrs...)
  246. }
  247. }
  248. // initialize with attrs, conds
  249. if len(tx.Statement.assigns) > 0 {
  250. tx.assignInterfacesToValue(tx.Statement.assigns...)
  251. }
  252. return
  253. }
  254. func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) (tx *DB) {
  255. queryTx := db.Limit(1).Order(clause.OrderByColumn{
  256. Column: clause.Column{Table: clause.CurrentTable, Name: clause.PrimaryKey},
  257. })
  258. if tx = queryTx.Find(dest, conds...); queryTx.RowsAffected == 0 {
  259. if c, ok := tx.Statement.Clauses["WHERE"]; ok {
  260. if where, ok := c.Expression.(clause.Where); ok {
  261. tx.assignInterfacesToValue(where.Exprs)
  262. }
  263. }
  264. // initialize with attrs, conds
  265. if len(tx.Statement.attrs) > 0 {
  266. tx.assignInterfacesToValue(tx.Statement.attrs...)
  267. }
  268. // initialize with attrs, conds
  269. if len(tx.Statement.assigns) > 0 {
  270. tx.assignInterfacesToValue(tx.Statement.assigns...)
  271. }
  272. return tx.Create(dest)
  273. } else if len(db.Statement.assigns) > 0 {
  274. exprs := tx.Statement.BuildCondition(tx.Statement.assigns[0], tx.Statement.assigns[1:]...)
  275. assigns := map[string]interface{}{}
  276. for _, expr := range exprs {
  277. if eq, ok := expr.(clause.Eq); ok {
  278. switch column := eq.Column.(type) {
  279. case string:
  280. assigns[column] = eq.Value
  281. case clause.Column:
  282. assigns[column.Name] = eq.Value
  283. default:
  284. }
  285. }
  286. }
  287. return tx.Model(dest).Updates(assigns)
  288. }
  289. return db
  290. }
  291. // Update update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields
  292. func (db *DB) Update(column string, value interface{}) (tx *DB) {
  293. tx = db.getInstance()
  294. tx.Statement.Dest = map[string]interface{}{column: value}
  295. tx.callbacks.Update().Execute(tx)
  296. return
  297. }
  298. // Updates update attributes with callbacks, refer: https://gorm.io/docs/update.html#Update-Changed-Fields
  299. func (db *DB) Updates(values interface{}) (tx *DB) {
  300. tx = db.getInstance()
  301. tx.Statement.Dest = values
  302. tx.callbacks.Update().Execute(tx)
  303. return
  304. }
  305. func (db *DB) UpdateColumn(column string, value interface{}) (tx *DB) {
  306. tx = db.getInstance()
  307. tx.Statement.Dest = map[string]interface{}{column: value}
  308. tx.Statement.SkipHooks = true
  309. tx.callbacks.Update().Execute(tx)
  310. return
  311. }
  312. func (db *DB) UpdateColumns(values interface{}) (tx *DB) {
  313. tx = db.getInstance()
  314. tx.Statement.Dest = values
  315. tx.Statement.SkipHooks = true
  316. tx.callbacks.Update().Execute(tx)
  317. return
  318. }
  319. // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
  320. func (db *DB) Delete(value interface{}, conds ...interface{}) (tx *DB) {
  321. tx = db.getInstance()
  322. if len(conds) > 0 {
  323. if exprs := tx.Statement.BuildCondition(conds[0], conds[1:]...); len(exprs) > 0 {
  324. tx.Statement.AddClause(clause.Where{Exprs: exprs})
  325. }
  326. }
  327. tx.Statement.Dest = value
  328. tx.callbacks.Delete().Execute(tx)
  329. return
  330. }
  331. func (db *DB) Count(count *int64) (tx *DB) {
  332. tx = db.getInstance()
  333. if tx.Statement.Model == nil {
  334. tx.Statement.Model = tx.Statement.Dest
  335. defer func() {
  336. tx.Statement.Model = nil
  337. }()
  338. }
  339. if selectClause, ok := db.Statement.Clauses["SELECT"]; ok {
  340. defer func() {
  341. db.Statement.Clauses["SELECT"] = selectClause
  342. }()
  343. } else {
  344. defer delete(tx.Statement.Clauses, "SELECT")
  345. }
  346. if len(tx.Statement.Selects) == 0 {
  347. tx.Statement.AddClause(clause.Select{Expression: clause.Expr{SQL: "count(1)"}})
  348. } else if !strings.HasPrefix(strings.TrimSpace(strings.ToLower(tx.Statement.Selects[0])), "count(") {
  349. expr := clause.Expr{SQL: "count(1)"}
  350. if len(tx.Statement.Selects) == 1 {
  351. dbName := tx.Statement.Selects[0]
  352. fields := strings.FieldsFunc(dbName, utils.IsValidDBNameChar)
  353. if len(fields) == 1 || (len(fields) == 3 && strings.ToUpper(fields[1]) == "AS") {
  354. if tx.Statement.Parse(tx.Statement.Model) == nil {
  355. if f := tx.Statement.Schema.LookUpField(dbName); f != nil {
  356. dbName = f.DBName
  357. }
  358. }
  359. if tx.Statement.Distinct {
  360. expr = clause.Expr{SQL: "COUNT(DISTINCT(?))", Vars: []interface{}{clause.Column{Name: dbName}}}
  361. } else {
  362. expr = clause.Expr{SQL: "COUNT(?)", Vars: []interface{}{clause.Column{Name: dbName}}}
  363. }
  364. }
  365. }
  366. tx.Statement.AddClause(clause.Select{Expression: expr})
  367. }
  368. if orderByClause, ok := db.Statement.Clauses["ORDER BY"]; ok {
  369. if _, ok := db.Statement.Clauses["GROUP BY"]; !ok {
  370. delete(db.Statement.Clauses, "ORDER BY")
  371. defer func() {
  372. db.Statement.Clauses["ORDER BY"] = orderByClause
  373. }()
  374. }
  375. }
  376. tx.Statement.Dest = count
  377. tx.callbacks.Query().Execute(tx)
  378. if tx.RowsAffected != 1 {
  379. *count = tx.RowsAffected
  380. }
  381. return
  382. }
  383. func (db *DB) Row() *sql.Row {
  384. tx := db.getInstance().InstanceSet("rows", false)
  385. tx.callbacks.Row().Execute(tx)
  386. row, ok := tx.Statement.Dest.(*sql.Row)
  387. if !ok && tx.DryRun {
  388. db.Logger.Error(tx.Statement.Context, ErrDryRunModeUnsupported.Error())
  389. }
  390. return row
  391. }
  392. func (db *DB) Rows() (*sql.Rows, error) {
  393. tx := db.getInstance().InstanceSet("rows", true)
  394. tx.callbacks.Row().Execute(tx)
  395. rows, ok := tx.Statement.Dest.(*sql.Rows)
  396. if !ok && tx.DryRun && tx.Error == nil {
  397. tx.Error = ErrDryRunModeUnsupported
  398. }
  399. return rows, tx.Error
  400. }
  401. // Scan scan value to a struct
  402. func (db *DB) Scan(dest interface{}) (tx *DB) {
  403. config := *db.Config
  404. currentLogger, newLogger := config.Logger, logger.Recorder.New()
  405. config.Logger = newLogger
  406. tx = db.getInstance()
  407. tx.Config = &config
  408. if rows, err := tx.Rows(); err != nil {
  409. tx.AddError(err)
  410. } else {
  411. defer rows.Close()
  412. if rows.Next() {
  413. tx.ScanRows(rows, dest)
  414. } else {
  415. tx.RowsAffected = 0
  416. }
  417. }
  418. currentLogger.Trace(tx.Statement.Context, newLogger.BeginAt, func() (string, int64) {
  419. return newLogger.SQL, tx.RowsAffected
  420. }, tx.Error)
  421. tx.Logger = currentLogger
  422. return
  423. }
  424. // Pluck used to query single column from a model as a map
  425. // var ages []int64
  426. // db.Find(&users).Pluck("age", &ages)
  427. func (db *DB) Pluck(column string, dest interface{}) (tx *DB) {
  428. tx = db.getInstance()
  429. if tx.Statement.Model != nil {
  430. if tx.Statement.Parse(tx.Statement.Model) == nil {
  431. if f := tx.Statement.Schema.LookUpField(column); f != nil {
  432. column = f.DBName
  433. }
  434. }
  435. } else if tx.Statement.Table == "" {
  436. tx.AddError(ErrModelValueRequired)
  437. }
  438. if len(tx.Statement.Selects) != 1 {
  439. fields := strings.FieldsFunc(column, utils.IsValidDBNameChar)
  440. tx.Statement.AddClauseIfNotExists(clause.Select{
  441. Distinct: tx.Statement.Distinct,
  442. Columns: []clause.Column{{Name: column, Raw: len(fields) != 1}},
  443. })
  444. }
  445. tx.Statement.Dest = dest
  446. tx.callbacks.Query().Execute(tx)
  447. return
  448. }
  449. func (db *DB) ScanRows(rows *sql.Rows, dest interface{}) error {
  450. tx := db.getInstance()
  451. if err := tx.Statement.Parse(dest); !errors.Is(err, schema.ErrUnsupportedDataType) {
  452. tx.AddError(err)
  453. }
  454. tx.Statement.Dest = dest
  455. tx.Statement.ReflectValue = reflect.ValueOf(dest)
  456. for tx.Statement.ReflectValue.Kind() == reflect.Ptr {
  457. tx.Statement.ReflectValue = tx.Statement.ReflectValue.Elem()
  458. }
  459. Scan(rows, tx, true)
  460. return tx.Error
  461. }
  462. // Transaction start a transaction as a block, return error will rollback, otherwise to commit.
  463. func (db *DB) Transaction(fc func(tx *DB) error, opts ...*sql.TxOptions) (err error) {
  464. panicked := true
  465. if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {
  466. // nested transaction
  467. if !db.DisableNestedTransaction {
  468. err = db.SavePoint(fmt.Sprintf("sp%p", fc)).Error
  469. defer func() {
  470. // Make sure to rollback when panic, Block error or Commit error
  471. if panicked || err != nil {
  472. db.RollbackTo(fmt.Sprintf("sp%p", fc))
  473. }
  474. }()
  475. }
  476. if err == nil {
  477. err = fc(db.Session(&Session{}))
  478. }
  479. } else {
  480. tx := db.Begin(opts...)
  481. defer func() {
  482. // Make sure to rollback when panic, Block error or Commit error
  483. if panicked || err != nil {
  484. tx.Rollback()
  485. }
  486. }()
  487. if err = tx.Error; err == nil {
  488. err = fc(tx)
  489. }
  490. if err == nil {
  491. err = tx.Commit().Error
  492. }
  493. }
  494. panicked = false
  495. return
  496. }
  497. // Begin begins a transaction
  498. func (db *DB) Begin(opts ...*sql.TxOptions) *DB {
  499. var (
  500. // clone statement
  501. tx = db.Session(&Session{Context: db.Statement.Context})
  502. opt *sql.TxOptions
  503. err error
  504. )
  505. if len(opts) > 0 {
  506. opt = opts[0]
  507. }
  508. if beginner, ok := tx.Statement.ConnPool.(TxBeginner); ok {
  509. tx.Statement.ConnPool, err = beginner.BeginTx(tx.Statement.Context, opt)
  510. } else if beginner, ok := tx.Statement.ConnPool.(ConnPoolBeginner); ok {
  511. tx.Statement.ConnPool, err = beginner.BeginTx(tx.Statement.Context, opt)
  512. } else {
  513. err = ErrInvalidTransaction
  514. }
  515. if err != nil {
  516. tx.AddError(err)
  517. }
  518. return tx
  519. }
  520. // Commit commit a transaction
  521. func (db *DB) Commit() *DB {
  522. if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil && !reflect.ValueOf(committer).IsNil() {
  523. db.AddError(committer.Commit())
  524. } else {
  525. db.AddError(ErrInvalidTransaction)
  526. }
  527. return db
  528. }
  529. // Rollback rollback a transaction
  530. func (db *DB) Rollback() *DB {
  531. if committer, ok := db.Statement.ConnPool.(TxCommitter); ok && committer != nil {
  532. if !reflect.ValueOf(committer).IsNil() {
  533. db.AddError(committer.Rollback())
  534. }
  535. } else {
  536. db.AddError(ErrInvalidTransaction)
  537. }
  538. return db
  539. }
  540. func (db *DB) SavePoint(name string) *DB {
  541. if savePointer, ok := db.Dialector.(SavePointerDialectorInterface); ok {
  542. db.AddError(savePointer.SavePoint(db, name))
  543. } else {
  544. db.AddError(ErrUnsupportedDriver)
  545. }
  546. return db
  547. }
  548. func (db *DB) RollbackTo(name string) *DB {
  549. if savePointer, ok := db.Dialector.(SavePointerDialectorInterface); ok {
  550. db.AddError(savePointer.RollbackTo(db, name))
  551. } else {
  552. db.AddError(ErrUnsupportedDriver)
  553. }
  554. return db
  555. }
  556. // Exec execute raw sql
  557. func (db *DB) Exec(sql string, values ...interface{}) (tx *DB) {
  558. tx = db.getInstance()
  559. tx.Statement.SQL = strings.Builder{}
  560. if strings.Contains(sql, "@") {
  561. clause.NamedExpr{SQL: sql, Vars: values}.Build(tx.Statement)
  562. } else {
  563. clause.Expr{SQL: sql, Vars: values}.Build(tx.Statement)
  564. }
  565. tx.callbacks.Raw().Execute(tx)
  566. return
  567. }