context.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. package sqlite3
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "math"
  6. "time"
  7. "github.com/ncruces/go-sqlite3/internal/util"
  8. )
  9. // Context is the context in which an SQL function executes.
  10. // An SQLite [Context] is in no way related to a Go [context.Context].
  11. //
  12. // https://sqlite.org/c3ref/context.html
  13. type Context struct {
  14. c *Conn
  15. handle ptr_t
  16. }
  17. // Conn returns the database connection of the
  18. // [Conn.CreateFunction] or [Conn.CreateWindowFunction]
  19. // routines that originally registered the application defined function.
  20. //
  21. // https://sqlite.org/c3ref/context_db_handle.html
  22. func (ctx Context) Conn() *Conn {
  23. return ctx.c
  24. }
  25. // SetAuxData saves metadata for argument n of the function.
  26. //
  27. // https://sqlite.org/c3ref/get_auxdata.html
  28. func (ctx Context) SetAuxData(n int, data any) {
  29. ptr := util.AddHandle(ctx.c.ctx, data)
  30. ctx.c.call("sqlite3_set_auxdata_go", stk_t(ctx.handle), stk_t(n), stk_t(ptr))
  31. }
  32. // GetAuxData returns metadata for argument n of the function.
  33. //
  34. // https://sqlite.org/c3ref/get_auxdata.html
  35. func (ctx Context) GetAuxData(n int) any {
  36. ptr := ptr_t(ctx.c.call("sqlite3_get_auxdata", stk_t(ctx.handle), stk_t(n)))
  37. return util.GetHandle(ctx.c.ctx, ptr)
  38. }
  39. // ResultBool sets the result of the function to a bool.
  40. // SQLite does not have a separate boolean storage class.
  41. // Instead, boolean values are stored as integers 0 (false) and 1 (true).
  42. //
  43. // https://sqlite.org/c3ref/result_blob.html
  44. func (ctx Context) ResultBool(value bool) {
  45. var i int64
  46. if value {
  47. i = 1
  48. }
  49. ctx.ResultInt64(i)
  50. }
  51. // ResultInt sets the result of the function to an int.
  52. //
  53. // https://sqlite.org/c3ref/result_blob.html
  54. func (ctx Context) ResultInt(value int) {
  55. ctx.ResultInt64(int64(value))
  56. }
  57. // ResultInt64 sets the result of the function to an int64.
  58. //
  59. // https://sqlite.org/c3ref/result_blob.html
  60. func (ctx Context) ResultInt64(value int64) {
  61. ctx.c.call("sqlite3_result_int64",
  62. stk_t(ctx.handle), stk_t(value))
  63. }
  64. // ResultFloat sets the result of the function to a float64.
  65. //
  66. // https://sqlite.org/c3ref/result_blob.html
  67. func (ctx Context) ResultFloat(value float64) {
  68. ctx.c.call("sqlite3_result_double",
  69. stk_t(ctx.handle), stk_t(math.Float64bits(value)))
  70. }
  71. // ResultText sets the result of the function to a string.
  72. //
  73. // https://sqlite.org/c3ref/result_blob.html
  74. func (ctx Context) ResultText(value string) {
  75. ptr := ctx.c.newString(value)
  76. ctx.c.call("sqlite3_result_text_go",
  77. stk_t(ctx.handle), stk_t(ptr), stk_t(len(value)))
  78. }
  79. // ResultRawText sets the text result of the function to a []byte.
  80. //
  81. // https://sqlite.org/c3ref/result_blob.html
  82. func (ctx Context) ResultRawText(value []byte) {
  83. if len(value) == 0 {
  84. ctx.ResultText("")
  85. return
  86. }
  87. ptr := ctx.c.newBytes(value)
  88. ctx.c.call("sqlite3_result_text_go",
  89. stk_t(ctx.handle), stk_t(ptr), stk_t(len(value)))
  90. }
  91. // ResultBlob sets the result of the function to a []byte.
  92. //
  93. // https://sqlite.org/c3ref/result_blob.html
  94. func (ctx Context) ResultBlob(value []byte) {
  95. if len(value) == 0 {
  96. ctx.ResultZeroBlob(0)
  97. return
  98. }
  99. ptr := ctx.c.newBytes(value)
  100. ctx.c.call("sqlite3_result_blob_go",
  101. stk_t(ctx.handle), stk_t(ptr), stk_t(len(value)))
  102. }
  103. // ResultZeroBlob sets the result of the function to a zero-filled, length n BLOB.
  104. //
  105. // https://sqlite.org/c3ref/result_blob.html
  106. func (ctx Context) ResultZeroBlob(n int64) {
  107. ctx.c.call("sqlite3_result_zeroblob64",
  108. stk_t(ctx.handle), stk_t(n))
  109. }
  110. // ResultNull sets the result of the function to NULL.
  111. //
  112. // https://sqlite.org/c3ref/result_blob.html
  113. func (ctx Context) ResultNull() {
  114. ctx.c.call("sqlite3_result_null",
  115. stk_t(ctx.handle))
  116. }
  117. // ResultTime sets the result of the function to a [time.Time].
  118. //
  119. // https://sqlite.org/c3ref/result_blob.html
  120. func (ctx Context) ResultTime(value time.Time, format TimeFormat) {
  121. switch format {
  122. case TimeFormatDefault, TimeFormatAuto, time.RFC3339Nano:
  123. ctx.resultRFC3339Nano(value)
  124. return
  125. }
  126. switch v := format.Encode(value).(type) {
  127. case string:
  128. ctx.ResultText(v)
  129. case int64:
  130. ctx.ResultInt64(v)
  131. case float64:
  132. ctx.ResultFloat(v)
  133. default:
  134. panic(util.AssertErr())
  135. }
  136. }
  137. func (ctx Context) resultRFC3339Nano(value time.Time) {
  138. const maxlen = int64(len(time.RFC3339Nano)) + 5
  139. ptr := ctx.c.new(maxlen)
  140. buf := util.View(ctx.c.mod, ptr, maxlen)
  141. buf = value.AppendFormat(buf[:0], time.RFC3339Nano)
  142. ctx.c.call("sqlite3_result_text_go",
  143. stk_t(ctx.handle), stk_t(ptr), stk_t(len(buf)))
  144. }
  145. // ResultPointer sets the result of the function to NULL, just like [Context.ResultNull],
  146. // except that it also associates ptr with that NULL value such that it can be retrieved
  147. // within an application-defined SQL function using [Value.Pointer].
  148. //
  149. // https://sqlite.org/c3ref/result_blob.html
  150. func (ctx Context) ResultPointer(ptr any) {
  151. valPtr := util.AddHandle(ctx.c.ctx, ptr)
  152. ctx.c.call("sqlite3_result_pointer_go",
  153. stk_t(ctx.handle), stk_t(valPtr))
  154. }
  155. // ResultJSON sets the result of the function to the JSON encoding of value.
  156. //
  157. // https://sqlite.org/c3ref/result_blob.html
  158. func (ctx Context) ResultJSON(value any) {
  159. data, err := json.Marshal(value)
  160. if err != nil {
  161. ctx.ResultError(err)
  162. return // notest
  163. }
  164. ctx.ResultRawText(data)
  165. }
  166. // ResultValue sets the result of the function to a copy of [Value].
  167. //
  168. // https://sqlite.org/c3ref/result_blob.html
  169. func (ctx Context) ResultValue(value Value) {
  170. if value.c != ctx.c {
  171. ctx.ResultError(MISUSE)
  172. return
  173. }
  174. ctx.c.call("sqlite3_result_value",
  175. stk_t(ctx.handle), stk_t(value.handle))
  176. }
  177. // ResultError sets the result of the function an error.
  178. //
  179. // https://sqlite.org/c3ref/result_blob.html
  180. func (ctx Context) ResultError(err error) {
  181. if errors.Is(err, NOMEM) {
  182. ctx.c.call("sqlite3_result_error_nomem", stk_t(ctx.handle))
  183. return
  184. }
  185. if errors.Is(err, TOOBIG) {
  186. ctx.c.call("sqlite3_result_error_toobig", stk_t(ctx.handle))
  187. return
  188. }
  189. msg, code := errorCode(err, _OK)
  190. if msg != "" {
  191. defer ctx.c.arena.mark()()
  192. ptr := ctx.c.arena.string(msg)
  193. ctx.c.call("sqlite3_result_error",
  194. stk_t(ctx.handle), stk_t(ptr), stk_t(len(msg)))
  195. }
  196. if code != _OK {
  197. ctx.c.call("sqlite3_result_error_code",
  198. stk_t(ctx.handle), stk_t(code))
  199. }
  200. }
  201. // VTabNoChange may return true if a column is being fetched as part
  202. // of an update during which the column value will not change.
  203. //
  204. // https://sqlite.org/c3ref/vtab_nochange.html
  205. func (ctx Context) VTabNoChange() bool {
  206. b := int32(ctx.c.call("sqlite3_vtab_nochange", stk_t(ctx.handle)))
  207. return b != 0
  208. }