sqlx_context.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. // +build go1.8
  2. package sqlx
  3. import (
  4. "context"
  5. "database/sql"
  6. "fmt"
  7. "io/ioutil"
  8. "path/filepath"
  9. "reflect"
  10. )
  11. // ConnectContext to a database and verify with a ping.
  12. func ConnectContext(ctx context.Context, driverName, dataSourceName string) (*DB, error) {
  13. db, err := Open(driverName, dataSourceName)
  14. if err != nil {
  15. return db, err
  16. }
  17. err = db.PingContext(ctx)
  18. return db, err
  19. }
  20. // QueryerContext is an interface used by GetContext and SelectContext
  21. type QueryerContext interface {
  22. QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
  23. QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error)
  24. QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row
  25. }
  26. // PreparerContext is an interface used by PreparexContext.
  27. type PreparerContext interface {
  28. PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
  29. }
  30. // ExecerContext is an interface used by MustExecContext and LoadFileContext
  31. type ExecerContext interface {
  32. ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
  33. }
  34. // ExtContext is a union interface which can bind, query, and exec, with Context
  35. // used by NamedQueryContext and NamedExecContext.
  36. type ExtContext interface {
  37. binder
  38. QueryerContext
  39. ExecerContext
  40. }
  41. // SelectContext executes a query using the provided Queryer, and StructScans
  42. // each row into dest, which must be a slice. If the slice elements are
  43. // scannable, then the result set must have only one column. Otherwise,
  44. // StructScan is used. The *sql.Rows are closed automatically.
  45. // Any placeholder parameters are replaced with supplied args.
  46. func SelectContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
  47. rows, err := q.QueryxContext(ctx, query, args...)
  48. if err != nil {
  49. return err
  50. }
  51. // if something happens here, we want to make sure the rows are Closed
  52. defer rows.Close()
  53. return scanAll(rows, dest, false)
  54. }
  55. // PreparexContext prepares a statement.
  56. //
  57. // The provided context is used for the preparation of the statement, not for
  58. // the execution of the statement.
  59. func PreparexContext(ctx context.Context, p PreparerContext, query string) (*Stmt, error) {
  60. s, err := p.PrepareContext(ctx, query)
  61. if err != nil {
  62. return nil, err
  63. }
  64. return &Stmt{Stmt: s, unsafe: isUnsafe(p), Mapper: mapperFor(p)}, err
  65. }
  66. // GetContext does a QueryRow using the provided Queryer, and scans the
  67. // resulting row to dest. If dest is scannable, the result must only have one
  68. // column. Otherwise, StructScan is used. Get will return sql.ErrNoRows like
  69. // row.Scan would. Any placeholder parameters are replaced with supplied args.
  70. // An error is returned if the result set is empty.
  71. func GetContext(ctx context.Context, q QueryerContext, dest interface{}, query string, args ...interface{}) error {
  72. r := q.QueryRowxContext(ctx, query, args...)
  73. return r.scanAny(dest, false)
  74. }
  75. // LoadFileContext exec's every statement in a file (as a single call to Exec).
  76. // LoadFileContext may return a nil *sql.Result if errors are encountered
  77. // locating or reading the file at path. LoadFile reads the entire file into
  78. // memory, so it is not suitable for loading large data dumps, but can be useful
  79. // for initializing schemas or loading indexes.
  80. //
  81. // FIXME: this does not really work with multi-statement files for mattn/go-sqlite3
  82. // or the go-mysql-driver/mysql drivers; pq seems to be an exception here. Detecting
  83. // this by requiring something with DriverName() and then attempting to split the
  84. // queries will be difficult to get right, and its current driver-specific behavior
  85. // is deemed at least not complex in its incorrectness.
  86. func LoadFileContext(ctx context.Context, e ExecerContext, path string) (*sql.Result, error) {
  87. realpath, err := filepath.Abs(path)
  88. if err != nil {
  89. return nil, err
  90. }
  91. contents, err := ioutil.ReadFile(realpath)
  92. if err != nil {
  93. return nil, err
  94. }
  95. res, err := e.ExecContext(ctx, string(contents))
  96. return &res, err
  97. }
  98. // MustExecContext execs the query using e and panics if there was an error.
  99. // Any placeholder parameters are replaced with supplied args.
  100. func MustExecContext(ctx context.Context, e ExecerContext, query string, args ...interface{}) sql.Result {
  101. res, err := e.ExecContext(ctx, query, args...)
  102. if err != nil {
  103. panic(err)
  104. }
  105. return res
  106. }
  107. // PrepareNamedContext returns an sqlx.NamedStmt
  108. func (db *DB) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
  109. return prepareNamedContext(ctx, db, query)
  110. }
  111. // NamedQueryContext using this DB.
  112. // Any named placeholder parameters are replaced with fields from arg.
  113. func (db *DB) NamedQueryContext(ctx context.Context, query string, arg interface{}) (*Rows, error) {
  114. return NamedQueryContext(ctx, db, query, arg)
  115. }
  116. // NamedExecContext using this DB.
  117. // Any named placeholder parameters are replaced with fields from arg.
  118. func (db *DB) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
  119. return NamedExecContext(ctx, db, query, arg)
  120. }
  121. // SelectContext using this DB.
  122. // Any placeholder parameters are replaced with supplied args.
  123. func (db *DB) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  124. return SelectContext(ctx, db, dest, query, args...)
  125. }
  126. // GetContext using this DB.
  127. // Any placeholder parameters are replaced with supplied args.
  128. // An error is returned if the result set is empty.
  129. func (db *DB) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  130. return GetContext(ctx, db, dest, query, args...)
  131. }
  132. // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
  133. //
  134. // The provided context is used for the preparation of the statement, not for
  135. // the execution of the statement.
  136. func (db *DB) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
  137. return PreparexContext(ctx, db, query)
  138. }
  139. // QueryxContext queries the database and returns an *sqlx.Rows.
  140. // Any placeholder parameters are replaced with supplied args.
  141. func (db *DB) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
  142. r, err := db.DB.QueryContext(ctx, query, args...)
  143. if err != nil {
  144. return nil, err
  145. }
  146. return &Rows{Rows: r, unsafe: db.unsafe, Mapper: db.Mapper}, err
  147. }
  148. // QueryRowxContext queries the database and returns an *sqlx.Row.
  149. // Any placeholder parameters are replaced with supplied args.
  150. func (db *DB) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
  151. rows, err := db.DB.QueryContext(ctx, query, args...)
  152. return &Row{rows: rows, err: err, unsafe: db.unsafe, Mapper: db.Mapper}
  153. }
  154. // MustBeginTx starts a transaction, and panics on error. Returns an *sqlx.Tx instead
  155. // of an *sql.Tx.
  156. //
  157. // The provided context is used until the transaction is committed or rolled
  158. // back. If the context is canceled, the sql package will roll back the
  159. // transaction. Tx.Commit will return an error if the context provided to
  160. // MustBeginContext is canceled.
  161. func (db *DB) MustBeginTx(ctx context.Context, opts *sql.TxOptions) *Tx {
  162. tx, err := db.BeginTxx(ctx, opts)
  163. if err != nil {
  164. panic(err)
  165. }
  166. return tx
  167. }
  168. // MustExecContext (panic) runs MustExec using this database.
  169. // Any placeholder parameters are replaced with supplied args.
  170. func (db *DB) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
  171. return MustExecContext(ctx, db, query, args...)
  172. }
  173. // BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
  174. // *sql.Tx.
  175. //
  176. // The provided context is used until the transaction is committed or rolled
  177. // back. If the context is canceled, the sql package will roll back the
  178. // transaction. Tx.Commit will return an error if the context provided to
  179. // BeginxContext is canceled.
  180. func (db *DB) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
  181. tx, err := db.DB.BeginTx(ctx, opts)
  182. if err != nil {
  183. return nil, err
  184. }
  185. return &Tx{Tx: tx, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, err
  186. }
  187. // Connx returns an *sqlx.Conn instead of an *sql.Conn.
  188. func (db *DB) Connx(ctx context.Context) (*Conn, error) {
  189. conn, err := db.DB.Conn(ctx)
  190. if err != nil {
  191. return nil, err
  192. }
  193. return &Conn{Conn: conn, driverName: db.driverName, unsafe: db.unsafe, Mapper: db.Mapper}, nil
  194. }
  195. // BeginTxx begins a transaction and returns an *sqlx.Tx instead of an
  196. // *sql.Tx.
  197. //
  198. // The provided context is used until the transaction is committed or rolled
  199. // back. If the context is canceled, the sql package will roll back the
  200. // transaction. Tx.Commit will return an error if the context provided to
  201. // BeginxContext is canceled.
  202. func (c *Conn) BeginTxx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) {
  203. tx, err := c.Conn.BeginTx(ctx, opts)
  204. if err != nil {
  205. return nil, err
  206. }
  207. return &Tx{Tx: tx, driverName: c.driverName, unsafe: c.unsafe, Mapper: c.Mapper}, err
  208. }
  209. // SelectContext using this Conn.
  210. // Any placeholder parameters are replaced with supplied args.
  211. func (c *Conn) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  212. return SelectContext(ctx, c, dest, query, args...)
  213. }
  214. // GetContext using this Conn.
  215. // Any placeholder parameters are replaced with supplied args.
  216. // An error is returned if the result set is empty.
  217. func (c *Conn) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  218. return GetContext(ctx, c, dest, query, args...)
  219. }
  220. // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
  221. //
  222. // The provided context is used for the preparation of the statement, not for
  223. // the execution of the statement.
  224. func (c *Conn) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
  225. return PreparexContext(ctx, c, query)
  226. }
  227. // QueryxContext queries the database and returns an *sqlx.Rows.
  228. // Any placeholder parameters are replaced with supplied args.
  229. func (c *Conn) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
  230. r, err := c.Conn.QueryContext(ctx, query, args...)
  231. if err != nil {
  232. return nil, err
  233. }
  234. return &Rows{Rows: r, unsafe: c.unsafe, Mapper: c.Mapper}, err
  235. }
  236. // QueryRowxContext queries the database and returns an *sqlx.Row.
  237. // Any placeholder parameters are replaced with supplied args.
  238. func (c *Conn) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
  239. rows, err := c.Conn.QueryContext(ctx, query, args...)
  240. return &Row{rows: rows, err: err, unsafe: c.unsafe, Mapper: c.Mapper}
  241. }
  242. // Rebind a query within a Conn's bindvar type.
  243. func (c *Conn) Rebind(query string) string {
  244. return Rebind(BindType(c.driverName), query)
  245. }
  246. // StmtxContext returns a version of the prepared statement which runs within a
  247. // transaction. Provided stmt can be either *sql.Stmt or *sqlx.Stmt.
  248. func (tx *Tx) StmtxContext(ctx context.Context, stmt interface{}) *Stmt {
  249. var s *sql.Stmt
  250. switch v := stmt.(type) {
  251. case Stmt:
  252. s = v.Stmt
  253. case *Stmt:
  254. s = v.Stmt
  255. case *sql.Stmt:
  256. s = v
  257. default:
  258. panic(fmt.Sprintf("non-statement type %v passed to Stmtx", reflect.ValueOf(stmt).Type()))
  259. }
  260. return &Stmt{Stmt: tx.StmtContext(ctx, s), Mapper: tx.Mapper}
  261. }
  262. // NamedStmtContext returns a version of the prepared statement which runs
  263. // within a transaction.
  264. func (tx *Tx) NamedStmtContext(ctx context.Context, stmt *NamedStmt) *NamedStmt {
  265. return &NamedStmt{
  266. QueryString: stmt.QueryString,
  267. Params: stmt.Params,
  268. Stmt: tx.StmtxContext(ctx, stmt.Stmt),
  269. }
  270. }
  271. // PreparexContext returns an sqlx.Stmt instead of a sql.Stmt.
  272. //
  273. // The provided context is used for the preparation of the statement, not for
  274. // the execution of the statement.
  275. func (tx *Tx) PreparexContext(ctx context.Context, query string) (*Stmt, error) {
  276. return PreparexContext(ctx, tx, query)
  277. }
  278. // PrepareNamedContext returns an sqlx.NamedStmt
  279. func (tx *Tx) PrepareNamedContext(ctx context.Context, query string) (*NamedStmt, error) {
  280. return prepareNamedContext(ctx, tx, query)
  281. }
  282. // MustExecContext runs MustExecContext within a transaction.
  283. // Any placeholder parameters are replaced with supplied args.
  284. func (tx *Tx) MustExecContext(ctx context.Context, query string, args ...interface{}) sql.Result {
  285. return MustExecContext(ctx, tx, query, args...)
  286. }
  287. // QueryxContext within a transaction and context.
  288. // Any placeholder parameters are replaced with supplied args.
  289. func (tx *Tx) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
  290. r, err := tx.Tx.QueryContext(ctx, query, args...)
  291. if err != nil {
  292. return nil, err
  293. }
  294. return &Rows{Rows: r, unsafe: tx.unsafe, Mapper: tx.Mapper}, err
  295. }
  296. // SelectContext within a transaction and context.
  297. // Any placeholder parameters are replaced with supplied args.
  298. func (tx *Tx) SelectContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  299. return SelectContext(ctx, tx, dest, query, args...)
  300. }
  301. // GetContext within a transaction and context.
  302. // Any placeholder parameters are replaced with supplied args.
  303. // An error is returned if the result set is empty.
  304. func (tx *Tx) GetContext(ctx context.Context, dest interface{}, query string, args ...interface{}) error {
  305. return GetContext(ctx, tx, dest, query, args...)
  306. }
  307. // QueryRowxContext within a transaction and context.
  308. // Any placeholder parameters are replaced with supplied args.
  309. func (tx *Tx) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
  310. rows, err := tx.Tx.QueryContext(ctx, query, args...)
  311. return &Row{rows: rows, err: err, unsafe: tx.unsafe, Mapper: tx.Mapper}
  312. }
  313. // NamedExecContext using this Tx.
  314. // Any named placeholder parameters are replaced with fields from arg.
  315. func (tx *Tx) NamedExecContext(ctx context.Context, query string, arg interface{}) (sql.Result, error) {
  316. return NamedExecContext(ctx, tx, query, arg)
  317. }
  318. // SelectContext using the prepared statement.
  319. // Any placeholder parameters are replaced with supplied args.
  320. func (s *Stmt) SelectContext(ctx context.Context, dest interface{}, args ...interface{}) error {
  321. return SelectContext(ctx, &qStmt{s}, dest, "", args...)
  322. }
  323. // GetContext using the prepared statement.
  324. // Any placeholder parameters are replaced with supplied args.
  325. // An error is returned if the result set is empty.
  326. func (s *Stmt) GetContext(ctx context.Context, dest interface{}, args ...interface{}) error {
  327. return GetContext(ctx, &qStmt{s}, dest, "", args...)
  328. }
  329. // MustExecContext (panic) using this statement. Note that the query portion of
  330. // the error output will be blank, as Stmt does not expose its query.
  331. // Any placeholder parameters are replaced with supplied args.
  332. func (s *Stmt) MustExecContext(ctx context.Context, args ...interface{}) sql.Result {
  333. return MustExecContext(ctx, &qStmt{s}, "", args...)
  334. }
  335. // QueryRowxContext using this statement.
  336. // Any placeholder parameters are replaced with supplied args.
  337. func (s *Stmt) QueryRowxContext(ctx context.Context, args ...interface{}) *Row {
  338. qs := &qStmt{s}
  339. return qs.QueryRowxContext(ctx, "", args...)
  340. }
  341. // QueryxContext using this statement.
  342. // Any placeholder parameters are replaced with supplied args.
  343. func (s *Stmt) QueryxContext(ctx context.Context, args ...interface{}) (*Rows, error) {
  344. qs := &qStmt{s}
  345. return qs.QueryxContext(ctx, "", args...)
  346. }
  347. func (q *qStmt) QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error) {
  348. return q.Stmt.QueryContext(ctx, args...)
  349. }
  350. func (q *qStmt) QueryxContext(ctx context.Context, query string, args ...interface{}) (*Rows, error) {
  351. r, err := q.Stmt.QueryContext(ctx, args...)
  352. if err != nil {
  353. return nil, err
  354. }
  355. return &Rows{Rows: r, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}, err
  356. }
  357. func (q *qStmt) QueryRowxContext(ctx context.Context, query string, args ...interface{}) *Row {
  358. rows, err := q.Stmt.QueryContext(ctx, args...)
  359. return &Row{rows: rows, err: err, unsafe: q.Stmt.unsafe, Mapper: q.Stmt.Mapper}
  360. }
  361. func (q *qStmt) ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error) {
  362. return q.Stmt.ExecContext(ctx, args...)
  363. }