session.go 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. // Copyright (c) 2018 David Crawshaw <david@zentus.com>
  2. //
  3. // Permission to use, copy, modify, and distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  8. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  10. // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  11. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  12. // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  13. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  14. package sqlite
  15. // #include <stdint.h>
  16. // #include <stdlib.h>
  17. // #include <sqlite3.h>
  18. // #include "wrappers.h"
  19. //
  20. // static int go_sqlite3session_changeset_strm(
  21. // sqlite3_session *pSession,
  22. // int (*xOutput)(void *pOut, const void *pData, int nData),
  23. // uintptr_t pOut
  24. // ) {
  25. // return sqlite3session_changeset_strm(pSession, xOutput, (void *)pOut);
  26. // }
  27. //
  28. // static int go_sqlite3session_patchset_strm(
  29. // sqlite3_session *pSession,
  30. // int (*xOutput)(void *pOut, const void *pData, int nData),
  31. // uintptr_t pOut
  32. // ) {
  33. // return sqlite3session_patchset_strm(pSession, xOutput, (void *)pOut);
  34. // }
  35. //
  36. // static int go_sqlite3changeset_invert_strm(
  37. // int (*xInput)(void *pIn, void *pData, int *pnData),
  38. // uintptr_t pIn,
  39. // int (*xOutput)(void *pOut, const void *pData, int nData),
  40. // uintptr_t pOut
  41. // ) {
  42. // return sqlite3changeset_invert_strm(xInput, (void *)pIn, xOutput, (void *)pOut);
  43. // }
  44. //
  45. // static int go_sqlite3changeset_apply_v2_strm(
  46. // sqlite3 *db, /* Apply change to "main" db of this handle */
  47. // int (*xInput)(void *pIn, void *pData, int *pnData), /* Input function */
  48. // uintptr_t pIn, /* First arg for xInput */
  49. // int(*xFilter)(
  50. // void *pCtx, /* Copy of sixth arg to _apply() */
  51. // const char *zTab /* Table name */
  52. // ),
  53. // int(*xConflict)(
  54. // void *pCtx, /* Copy of sixth arg to _apply() */
  55. // int eConflict, /* DATA, MISSING, CONFLICT, CONSTRAINT */
  56. // sqlite3_changeset_iter *p /* Handle describing change and conflict */
  57. // ),
  58. // uintptr_t pCtx, /* First argument passed to xConflict */
  59. // void **ppRebase, int *pnRebase,
  60. // int flags
  61. // ) {
  62. // return sqlite3changeset_apply_v2_strm(db,
  63. // xInput,
  64. // (void *)pIn,
  65. // xFilter,
  66. // xConflict,
  67. // (void *)pCtx,
  68. // ppRebase,
  69. // pnRebase,
  70. // flags
  71. // );
  72. // }
  73. //
  74. // static int go_sqlite3changeset_concat_strm(
  75. // int (*xInputA)(void *pIn, void *pData, int *pnData),
  76. // uintptr_t pInA,
  77. // int (*xInputB)(void *pIn, void *pData, int *pnData),
  78. // uintptr_t pInB,
  79. // int (*xOutput)(void *pOut, const void *pData, int nData),
  80. // uintptr_t pOut
  81. // ) {
  82. // return sqlite3changeset_concat_strm(
  83. // xInputA, (void *)pInA,
  84. // xInputB, (void *)pInB,
  85. // xOutput, (void *)pOut
  86. // );
  87. // }
  88. //
  89. // static int go_sqlite3changeset_start_strm(
  90. // sqlite3_changeset_iter **pp,
  91. // int (*xInput)(void *pIn, void *pData, int *pnData),
  92. // uintptr_t pIn
  93. // ) {
  94. // return sqlite3changeset_start_strm(pp, xInput, (void *)pIn);
  95. // }
  96. //
  97. // static int go_sqlite3changegroup_add_strm(sqlite3_changegroup* g,
  98. // int (*xInput)(void *pIn, void *pData, int *pnData),
  99. // uintptr_t pIn
  100. // ) {
  101. // return sqlite3changegroup_add_strm(g, xInput, (void *)pIn);
  102. // }
  103. //
  104. // static int go_sqlite3changegroup_output_strm(sqlite3_changegroup* g,
  105. // int (*xOutput)(void *pOut, const void *pData, int nData),
  106. // uintptr_t pOut
  107. // ) {
  108. // return sqlite3changegroup_output_strm(g, xOutput, (void *)pOut);
  109. // }
  110. import "C"
  111. import (
  112. "io"
  113. "runtime"
  114. "sync"
  115. "unsafe"
  116. )
  117. // A Session tracks database changes made by a Conn.
  118. //
  119. // It is used to build changesets.
  120. //
  121. // Equivalent to the sqlite3_session* C object.
  122. type Session struct {
  123. ptr *C.sqlite3_session
  124. }
  125. // CreateSession creates a new session object.
  126. // If db is "", then a default of "main" is used.
  127. //
  128. // https://www.sqlite.org/session/sqlite3session_create.html
  129. func (conn *Conn) CreateSession(db string) (*Session, error) {
  130. var cdb *C.char
  131. if db == "" || db == "main" {
  132. cdb = cmain
  133. } else {
  134. cdb = C.CString(db)
  135. defer C.free(unsafe.Pointer(cdb))
  136. }
  137. s := &Session{}
  138. res := C.sqlite3session_create(conn.conn, cdb, &s.ptr)
  139. if err := conn.reserr("Conn.CreateSession", db, res); err != nil {
  140. return nil, err
  141. }
  142. runtime.SetFinalizer(s, func(s *Session) {
  143. if s.ptr != nil {
  144. panic("open *sqlite.Session garbage collected, call Delete method")
  145. }
  146. })
  147. return s, nil
  148. }
  149. // Delete deletes a Session object.
  150. //
  151. // https://www.sqlite.org/session/sqlite3session_delete.html
  152. func (s *Session) Delete() {
  153. C.sqlite3session_delete(s.ptr)
  154. s.ptr = nil
  155. }
  156. // Enable enables recording of changes by a Session.
  157. // New Sessions start enabled.
  158. //
  159. // https://www.sqlite.org/session/sqlite3session_enable.html
  160. func (s *Session) Enable() { C.sqlite3session_enable(s.ptr, 1) }
  161. // Disable disables recording of changes by a Session.
  162. //
  163. // https://www.sqlite.org/session/sqlite3session_enable.html
  164. func (s *Session) Disable() { C.sqlite3session_enable(s.ptr, 0) }
  165. // Attach attaches a table to the session object.
  166. // Changes made to the table will be tracked by the session.
  167. //
  168. // An empty tableName attaches all the tables in the database.
  169. func (s *Session) Attach(tableName string) error {
  170. var ctable *C.char
  171. if tableName != "" {
  172. ctable = C.CString(tableName)
  173. defer C.free(unsafe.Pointer(ctable))
  174. }
  175. res := C.sqlite3session_attach(s.ptr, ctable)
  176. return reserr("Session.Attach", tableName, "", res)
  177. }
  178. // Diff appends the difference between two tables (srcDB and the session DB) to the session.
  179. // The two tables must have the same name and schema.
  180. func (s *Session) Diff(srcDB, tableName string) error {
  181. var errmsg *C.char
  182. csrcDB := C.CString(srcDB)
  183. ctable := C.CString(tableName)
  184. defer func() {
  185. C.free(unsafe.Pointer(csrcDB))
  186. C.free(unsafe.Pointer(ctable))
  187. if errmsg != nil {
  188. C.free(unsafe.Pointer(errmsg))
  189. }
  190. }()
  191. res := C.sqlite3session_diff(s.ptr, csrcDB, ctable, &errmsg)
  192. if res != 0 {
  193. return reserr("Session.Diff", srcDB+"."+tableName, C.GoString(errmsg), res)
  194. }
  195. return nil
  196. }
  197. // Changeset generates a changeset from a session.
  198. //
  199. // https://www.sqlite.org/session/sqlite3session_changeset.html
  200. func (s *Session) Changeset(w io.Writer) error {
  201. x := newStrm(w, nil)
  202. defer x.free()
  203. res := C.go_sqlite3session_changeset_strm(s.ptr, (*[0]byte)(C.c_strm_w_tramp), x.cptr())
  204. return reserr("Session.Changeset", "", "", res)
  205. }
  206. // Patchset generates a patchset from a session.
  207. //
  208. // https://www.sqlite.org/session/sqlite3session_patchset.html
  209. func (s *Session) Patchset(w io.Writer) error {
  210. x := newStrm(w, nil)
  211. defer x.free()
  212. res := C.go_sqlite3session_patchset_strm(s.ptr, (*[0]byte)(C.c_strm_w_tramp), x.cptr())
  213. return reserr("Session.Patchset", "", "", res)
  214. }
  215. // ChangesetApply applies a changeset to the database.
  216. //
  217. // If a changeset will not apply cleanly then conflictFn can be used to resolve
  218. // the conflict. See the SQLite documentation for full details.
  219. //
  220. // https://www.sqlite.org/session/sqlite3changeset_apply.html
  221. func (conn *Conn) ChangesetApply(r io.Reader,
  222. filterFn func(tableName string) bool,
  223. conflictFn func(ConflictType, ChangesetIter) ConflictAction) error {
  224. return conn.changesetApply(r, filterFn, conflictFn, false)
  225. }
  226. // ChangesetApplyInverse applies the inverse of a changeset to the database.
  227. //
  228. // If a changeset will not apply cleanly then conflictFn can be used to resolve
  229. // the conflict. See the SQLite documentation for full details.
  230. //
  231. // This is equivalent to inverting a changeset using ChangesetInvert before
  232. // applying it. It is an error to use a patchset.
  233. //
  234. // https://www.sqlite.org/session/sqlite3changeset_apply.html
  235. //
  236. // https://www.sqlite.org/session/c_changesetapply_invert.html
  237. //
  238. // https://www.sqlite.org/session/sqlite3changeset_invert.html
  239. func (conn *Conn) ChangesetApplyInverse(r io.Reader,
  240. filterFn func(tableName string) bool,
  241. conflictFn func(ConflictType, ChangesetIter) ConflictAction) error {
  242. return conn.changesetApply(r, filterFn, conflictFn, true)
  243. }
  244. func (conn *Conn) changesetApply(r io.Reader,
  245. filterFn func(tableName string) bool,
  246. conflictFn func(ConflictType, ChangesetIter) ConflictAction,
  247. invert bool) error {
  248. xIn := newStrm(nil, r)
  249. x := &xapply{
  250. conn: conn,
  251. filterFn: filterFn,
  252. conflictFn: conflictFn,
  253. }
  254. xapplys.mu.Lock()
  255. xapplys.next++
  256. x.id = xapplys.next
  257. xapplys.m[x.id] = x
  258. xapplys.mu.Unlock()
  259. var filterTramp, conflictTramp *[0]byte
  260. if x.filterFn != nil {
  261. filterTramp = (*[0]byte)(C.c_xapply_filter_tramp)
  262. }
  263. if x.conflictFn != nil {
  264. conflictTramp = (*[0]byte)(C.c_xapply_conflict_tramp)
  265. }
  266. var flags C.int
  267. if invert {
  268. flags = C.SQLITE_CHANGESETAPPLY_INVERT
  269. }
  270. pCtx := (C.uintptr_t)(x.id)
  271. res := C.go_sqlite3changeset_apply_v2_strm(conn.conn,
  272. (*[0]byte)(C.c_strm_r_tramp),
  273. xIn.cptr(),
  274. filterTramp, conflictTramp,
  275. pCtx,
  276. nil, nil,
  277. flags)
  278. xapplys.mu.Lock()
  279. delete(xapplys.m, x.id)
  280. xapplys.mu.Unlock()
  281. xIn.free()
  282. return conn.reserr("Conn.ChangesetApply", "", res)
  283. }
  284. // ChangesetInvert inverts a changeset.
  285. //
  286. // https://www.sqlite.org/session/sqlite3changeset_invert.html
  287. func ChangesetInvert(w io.Writer, r io.Reader) error {
  288. xIn := newStrm(nil, r)
  289. xOut := newStrm(w, nil)
  290. res := C.go_sqlite3changeset_invert_strm(
  291. (*[0]byte)(C.c_strm_r_tramp), xIn.cptr(),
  292. (*[0]byte)(C.c_strm_w_tramp), xOut.cptr(),
  293. )
  294. xIn.free()
  295. xOut.free()
  296. return reserr("ChangesetInvert", "", "", res)
  297. }
  298. // ChangesetConcat concatenates two changesets.
  299. //
  300. // https://www.sqlite.org/session/sqlite3changeset_concat.html
  301. func ChangesetConcat(w io.Writer, r1, r2 io.Reader) error {
  302. xInA := newStrm(nil, r1)
  303. xInB := newStrm(nil, r2)
  304. xOut := newStrm(w, nil)
  305. res := C.go_sqlite3changeset_concat_strm(
  306. (*[0]byte)(C.c_strm_r_tramp), xInA.cptr(),
  307. (*[0]byte)(C.c_strm_r_tramp), xInB.cptr(),
  308. (*[0]byte)(C.c_strm_w_tramp), xOut.cptr(),
  309. )
  310. xInA.free()
  311. xInB.free()
  312. xOut.free()
  313. return reserr("ChangesetConcat", "", "", res)
  314. }
  315. // ChangesetIter is an iterator over a changeset.
  316. //
  317. // An iterator is used much like a Stmt over result rows.
  318. // It is also used in the conflictFn provided to ChangesetApply.
  319. // To process the changes in a changeset:
  320. //
  321. // iter, err := ChangesetIterStart(r)
  322. // if err != nil {
  323. // // ... handle err
  324. // }
  325. // for {
  326. // hasRow, err := iter.Next()
  327. // if err != nil {
  328. // // ... handle err
  329. // }
  330. // if !hasRow {
  331. // break
  332. // }
  333. // // Use the Op, New, Old method to inspect the change.
  334. // }
  335. // if err := iter.Finalize(); err != nil {
  336. // // ... handle err
  337. // }
  338. type ChangesetIter struct {
  339. ptr *C.sqlite3_changeset_iter
  340. xIn *strm
  341. }
  342. // ChangesetIterStart creates an iterator over a changeset.
  343. //
  344. // https://www.sqlite.org/session/sqlite3changeset_start.html
  345. func ChangesetIterStart(r io.Reader) (ChangesetIter, error) {
  346. iter := ChangesetIter{}
  347. iter.xIn = newStrm(nil, r)
  348. res := C.go_sqlite3changeset_start_strm(
  349. &iter.ptr,
  350. (*[0]byte)(C.c_strm_r_tramp),
  351. iter.xIn.cptr())
  352. if err := reserr("ChangesetIterStart", "", "", res); err != nil {
  353. return ChangesetIter{}, err
  354. }
  355. return iter, nil
  356. }
  357. // Finalize deletes a changeset iterator.
  358. // Do not use in iterators passed to a ChangesetApply conflictFn.
  359. //
  360. // https://www.sqlite.org/session/sqlite3changeset_finalize.html
  361. func (iter ChangesetIter) Finalize() error {
  362. res := C.sqlite3changeset_finalize(iter.ptr)
  363. iter.ptr = nil
  364. if iter.xIn != nil {
  365. iter.xIn.free()
  366. iter.xIn = nil
  367. }
  368. return reserr("ChangesetIter.Finalize", "", "", res)
  369. }
  370. // Old obtains old row values from an iterator.
  371. //
  372. // https://www.sqlite.org/session/sqlite3changeset_old.html
  373. func (iter ChangesetIter) Old(col int) (v Value, err error) {
  374. res := C.sqlite3changeset_old(iter.ptr, C.int(col), &v.ptr)
  375. if err := reserr("ChangesetIter.Old", "", "", res); err != nil {
  376. return Value{}, err
  377. }
  378. return v, nil
  379. }
  380. // New obtains new row values from an iterator.
  381. //
  382. // https://www.sqlite.org/session/sqlite3changeset_new.html
  383. func (iter ChangesetIter) New(col int) (v Value, err error) {
  384. res := C.sqlite3changeset_new(iter.ptr, C.int(col), &v.ptr)
  385. if err := reserr("ChangesetIter.New", "", "", res); err != nil {
  386. return Value{}, err
  387. }
  388. return v, nil
  389. }
  390. // Conflict obtains conflicting row values from an iterator.
  391. // Only use this in an iterator passed to a ChangesetApply conflictFn.
  392. //
  393. // https://www.sqlite.org/session/sqlite3changeset_conflict.html
  394. func (iter ChangesetIter) Conflict(col int) (v Value, err error) {
  395. res := C.sqlite3changeset_conflict(iter.ptr, C.int(col), &v.ptr)
  396. if err := reserr("ChangesetIter.Conflict", "", "", res); err != nil {
  397. return Value{}, err
  398. }
  399. return v, nil
  400. }
  401. // Next moves a changeset iterator forward.
  402. // Do not use in iterators passed to a ChangesetApply conflictFn.
  403. //
  404. // https://www.sqlite.org/session/sqlite3changeset_next.html
  405. func (iter ChangesetIter) Next() (rowReturned bool, err error) {
  406. switch res := C.sqlite3changeset_next(iter.ptr); res {
  407. case C.SQLITE_ROW:
  408. return true, nil
  409. case C.SQLITE_DONE:
  410. return false, nil
  411. default:
  412. return false, reserr("ChangesetIter.Next", "", "", res)
  413. }
  414. }
  415. // Op reports details about the current operation in the iterator.
  416. //
  417. // https://www.sqlite.org/session/sqlite3changeset_op.html
  418. func (iter ChangesetIter) Op() (table string, numCols int, opType OpType, indirect bool, err error) {
  419. var pzTab *C.char
  420. var pnCol, pOp, pbIndirect C.int
  421. res := C.sqlite3changeset_op(iter.ptr, &pzTab, &pnCol, &pOp, &pbIndirect)
  422. if err := reserr("ChangesetIter.Op", "", "", res); err != nil {
  423. return "", 0, 0, false, err
  424. }
  425. table = C.GoString(pzTab)
  426. numCols = int(pnCol)
  427. opType = OpType(pOp)
  428. if pbIndirect != 0 {
  429. indirect = true
  430. }
  431. return table, numCols, opType, indirect, nil
  432. }
  433. // FKConflicts reports the number of foreign key constraint violations.
  434. //
  435. // https://www.sqlite.org/session/sqlite3changeset_fk_conflicts.html
  436. func (iter ChangesetIter) FKConflicts() (int, error) {
  437. var pnOut C.int
  438. res := C.sqlite3changeset_fk_conflicts(iter.ptr, &pnOut)
  439. if err := reserr("ChangesetIter.FKConflicts", "", "", res); err != nil {
  440. return 0, err
  441. }
  442. return int(pnOut), nil
  443. }
  444. // PK reports the columns that make up the primary key.
  445. //
  446. // https://www.sqlite.org/session/sqlite3changeset_pk.html
  447. func (iter ChangesetIter) PK() ([]bool, error) {
  448. var pabPK *C.uchar
  449. var pnCol C.int
  450. res := C.sqlite3changeset_pk(iter.ptr, &pabPK, &pnCol)
  451. if err := reserr("ChangesetIter.PK", "", "", res); err != nil {
  452. return nil, err
  453. }
  454. vals := (*[127]byte)(unsafe.Pointer(pabPK))[:pnCol:pnCol]
  455. cols := make([]bool, pnCol)
  456. for i, val := range vals {
  457. if val != 0 {
  458. cols[i] = true
  459. }
  460. }
  461. return cols, nil
  462. }
  463. // OpType is an enumeration of SQLite statements. Used for authorization and
  464. // changeset details.
  465. type OpType int
  466. // Operation types
  467. const (
  468. SQLITE_CREATE_INDEX OpType = C.SQLITE_CREATE_INDEX
  469. SQLITE_CREATE_TABLE OpType = C.SQLITE_CREATE_TABLE
  470. SQLITE_CREATE_TEMP_INDEX OpType = C.SQLITE_CREATE_TEMP_INDEX
  471. SQLITE_CREATE_TEMP_TABLE OpType = C.SQLITE_CREATE_TEMP_TABLE
  472. SQLITE_CREATE_TEMP_TRIGGER OpType = C.SQLITE_CREATE_TEMP_TRIGGER
  473. SQLITE_CREATE_TEMP_VIEW OpType = C.SQLITE_CREATE_TEMP_VIEW
  474. SQLITE_CREATE_TRIGGER OpType = C.SQLITE_CREATE_TRIGGER
  475. SQLITE_CREATE_VIEW OpType = C.SQLITE_CREATE_VIEW
  476. SQLITE_DELETE OpType = C.SQLITE_DELETE
  477. SQLITE_DROP_INDEX OpType = C.SQLITE_DROP_INDEX
  478. SQLITE_DROP_TABLE OpType = C.SQLITE_DROP_TABLE
  479. SQLITE_DROP_TEMP_INDEX OpType = C.SQLITE_DROP_TEMP_INDEX
  480. SQLITE_DROP_TEMP_TABLE OpType = C.SQLITE_DROP_TEMP_TABLE
  481. SQLITE_DROP_TEMP_TRIGGER OpType = C.SQLITE_DROP_TEMP_TRIGGER
  482. SQLITE_DROP_TEMP_VIEW OpType = C.SQLITE_DROP_TEMP_VIEW
  483. SQLITE_DROP_TRIGGER OpType = C.SQLITE_DROP_TRIGGER
  484. SQLITE_DROP_VIEW OpType = C.SQLITE_DROP_VIEW
  485. SQLITE_INSERT OpType = C.SQLITE_INSERT
  486. SQLITE_PRAGMA OpType = C.SQLITE_PRAGMA
  487. SQLITE_READ OpType = C.SQLITE_READ
  488. SQLITE_SELECT OpType = C.SQLITE_SELECT
  489. SQLITE_TRANSACTION OpType = C.SQLITE_TRANSACTION
  490. SQLITE_UPDATE OpType = C.SQLITE_UPDATE
  491. SQLITE_ATTACH OpType = C.SQLITE_ATTACH
  492. SQLITE_DETACH OpType = C.SQLITE_DETACH
  493. SQLITE_ALTER_TABLE OpType = C.SQLITE_ALTER_TABLE
  494. SQLITE_REINDEX OpType = C.SQLITE_REINDEX
  495. SQLITE_ANALYZE OpType = C.SQLITE_ANALYZE
  496. SQLITE_CREATE_VTABLE OpType = C.SQLITE_CREATE_VTABLE
  497. SQLITE_DROP_VTABLE OpType = C.SQLITE_DROP_VTABLE
  498. SQLITE_FUNCTION OpType = C.SQLITE_FUNCTION
  499. SQLITE_SAVEPOINT OpType = C.SQLITE_SAVEPOINT
  500. SQLITE_COPY OpType = C.SQLITE_COPY
  501. SQLITE_RECURSIVE OpType = C.SQLITE_RECURSIVE
  502. )
  503. func (opType OpType) String() string {
  504. switch opType {
  505. default:
  506. var buf [20]byte
  507. return "SQLITE_UNKNOWN_OP_TYPE(" + string(itoa(buf[:], int64(opType))) + ")"
  508. case SQLITE_CREATE_INDEX:
  509. return "SQLITE_CREATE_INDEX"
  510. case SQLITE_CREATE_TABLE:
  511. return "SQLITE_CREATE_TABLE"
  512. case SQLITE_CREATE_TEMP_INDEX:
  513. return "SQLITE_CREATE_TEMP_INDEX"
  514. case SQLITE_CREATE_TEMP_TABLE:
  515. return "SQLITE_CREATE_TEMP_TABLE"
  516. case SQLITE_CREATE_TEMP_TRIGGER:
  517. return "SQLITE_CREATE_TEMP_TRIGGER"
  518. case SQLITE_CREATE_TEMP_VIEW:
  519. return "SQLITE_CREATE_TEMP_VIEW"
  520. case SQLITE_CREATE_TRIGGER:
  521. return "SQLITE_CREATE_TRIGGER"
  522. case SQLITE_CREATE_VIEW:
  523. return "SQLITE_CREATE_VIEW"
  524. case SQLITE_DELETE:
  525. return "SQLITE_DELETE"
  526. case SQLITE_DROP_INDEX:
  527. return "SQLITE_DROP_INDEX"
  528. case SQLITE_DROP_TABLE:
  529. return "SQLITE_DROP_TABLE"
  530. case SQLITE_DROP_TEMP_INDEX:
  531. return "SQLITE_DROP_TEMP_INDEX"
  532. case SQLITE_DROP_TEMP_TABLE:
  533. return "SQLITE_DROP_TEMP_TABLE"
  534. case SQLITE_DROP_TEMP_TRIGGER:
  535. return "SQLITE_DROP_TEMP_TRIGGER"
  536. case SQLITE_DROP_TEMP_VIEW:
  537. return "SQLITE_DROP_TEMP_VIEW"
  538. case SQLITE_DROP_TRIGGER:
  539. return "SQLITE_DROP_TRIGGER"
  540. case SQLITE_DROP_VIEW:
  541. return "SQLITE_DROP_VIEW"
  542. case SQLITE_INSERT:
  543. return "SQLITE_INSERT"
  544. case SQLITE_PRAGMA:
  545. return "SQLITE_PRAGMA"
  546. case SQLITE_READ:
  547. return "SQLITE_READ"
  548. case SQLITE_SELECT:
  549. return "SQLITE_SELECT"
  550. case SQLITE_TRANSACTION:
  551. return "SQLITE_TRANSACTION"
  552. case SQLITE_UPDATE:
  553. return "SQLITE_UPDATE"
  554. case SQLITE_ATTACH:
  555. return "SQLITE_ATTACH"
  556. case SQLITE_DETACH:
  557. return "SQLITE_DETACH"
  558. case SQLITE_ALTER_TABLE:
  559. return "SQLITE_ALTER_TABLE"
  560. case SQLITE_REINDEX:
  561. return "SQLITE_REINDEX"
  562. case SQLITE_ANALYZE:
  563. return "SQLITE_ANALYZE"
  564. case SQLITE_CREATE_VTABLE:
  565. return "SQLITE_CREATE_VTABLE"
  566. case SQLITE_DROP_VTABLE:
  567. return "SQLITE_DROP_VTABLE"
  568. case SQLITE_FUNCTION:
  569. return "SQLITE_FUNCTION"
  570. case SQLITE_SAVEPOINT:
  571. return "SQLITE_SAVEPOINT"
  572. case SQLITE_COPY:
  573. return "SQLITE_COPY"
  574. case SQLITE_RECURSIVE:
  575. return "SQLITE_RECURSIVE"
  576. }
  577. }
  578. type ConflictType int
  579. const (
  580. SQLITE_CHANGESET_DATA = ConflictType(C.SQLITE_CHANGESET_DATA)
  581. SQLITE_CHANGESET_NOTFOUND = ConflictType(C.SQLITE_CHANGESET_NOTFOUND)
  582. SQLITE_CHANGESET_CONFLICT = ConflictType(C.SQLITE_CHANGESET_CONFLICT)
  583. SQLITE_CHANGESET_CONSTRAINT = ConflictType(C.SQLITE_CHANGESET_CONSTRAINT)
  584. SQLITE_CHANGESET_FOREIGN_KEY = ConflictType(C.SQLITE_CHANGESET_FOREIGN_KEY)
  585. )
  586. func (code ConflictType) String() string {
  587. switch code {
  588. default:
  589. var buf [20]byte
  590. return "SQLITE_UNKNOWN_CONFLICT_TYPE(" + string(itoa(buf[:], int64(code))) + ")"
  591. case SQLITE_CHANGESET_DATA:
  592. return "SQLITE_CHANGESET_DATA"
  593. case SQLITE_CHANGESET_NOTFOUND:
  594. return "SQLITE_CHANGESET_NOTFOUND"
  595. case SQLITE_CHANGESET_CONFLICT:
  596. return "SQLITE_CHANGESET_CONFLICT"
  597. case SQLITE_CHANGESET_CONSTRAINT:
  598. return "SQLITE_CHANGESET_CONSTRAINT"
  599. case SQLITE_CHANGESET_FOREIGN_KEY:
  600. return "SQLITE_CHANGESET_FOREIGN_KEY"
  601. }
  602. }
  603. type ConflictAction int
  604. const (
  605. SQLITE_CHANGESET_OMIT = ConflictAction(C.SQLITE_CHANGESET_OMIT)
  606. SQLITE_CHANGESET_ABORT = ConflictAction(C.SQLITE_CHANGESET_ABORT)
  607. SQLITE_CHANGESET_REPLACE = ConflictAction(C.SQLITE_CHANGESET_REPLACE)
  608. )
  609. func (code ConflictAction) String() string {
  610. switch code {
  611. default:
  612. var buf [20]byte
  613. return "SQLITE_UNKNOWN_CONFLICT_ACTION(" + string(itoa(buf[:], int64(code))) + ")"
  614. case SQLITE_CHANGESET_OMIT:
  615. return "SQLITE_CHANGESET_OMIT"
  616. case SQLITE_CHANGESET_ABORT:
  617. return "SQLITE_CHANGESET_ABORT"
  618. case SQLITE_CHANGESET_REPLACE:
  619. return "SQLITE_CHANGESET_REPLACE"
  620. }
  621. }
  622. type Changegroup struct {
  623. ptr *C.sqlite3_changegroup
  624. }
  625. // https://www.sqlite.org/session/sqlite3changegroup_new.html
  626. func NewChangegroup() (*Changegroup, error) {
  627. c := &Changegroup{}
  628. res := C.sqlite3changegroup_new(&c.ptr)
  629. if err := reserr("NewChangegroup", "", "", res); err != nil {
  630. return nil, err
  631. }
  632. return c, nil
  633. }
  634. // https://www.sqlite.org/session/sqlite3changegroup_add.html
  635. func (cg Changegroup) Add(r io.Reader) error {
  636. xIn := newStrm(nil, r)
  637. res := C.go_sqlite3changegroup_add_strm(
  638. cg.ptr,
  639. (*[0]byte)(C.c_strm_r_tramp),
  640. xIn.cptr())
  641. xIn.free()
  642. return reserr("Changegroup.Add", "", "", res)
  643. }
  644. // Delete a Changegroup.
  645. //
  646. // https://www.sqlite.org/session/sqlite3changegroup_delete.html
  647. func (cg Changegroup) Delete() {
  648. C.sqlite3changegroup_delete(cg.ptr)
  649. }
  650. // https://www.sqlite.org/session/sqlite3changegroup_output.html
  651. func (cg Changegroup) Output(w io.Writer) (n int, err error) {
  652. xOut := newStrm(w, nil)
  653. res := C.go_sqlite3changegroup_output_strm(
  654. cg.ptr,
  655. (*[0]byte)(C.c_strm_w_tramp),
  656. xOut.cptr())
  657. n = xOut.n
  658. xOut.free()
  659. return n, reserr("Changegroup.Output", "", "", res)
  660. }
  661. type strm struct {
  662. id int
  663. w io.Writer // one of w or r is set
  664. r io.Reader
  665. n int // number of bytes read or written
  666. }
  667. var strms = struct {
  668. mu sync.RWMutex
  669. m map[int]*strm
  670. next int
  671. }{
  672. m: make(map[int]*strm),
  673. }
  674. func newStrm(w io.Writer, r io.Reader) *strm {
  675. x := &strm{w: w, r: r}
  676. strms.mu.Lock()
  677. strms.next++
  678. x.id = strms.next
  679. strms.m[x.id] = x
  680. strms.mu.Unlock()
  681. return x
  682. }
  683. func (x strm) free() {
  684. strms.mu.Lock()
  685. delete(strms.m, x.id)
  686. strms.mu.Unlock()
  687. }
  688. func (x *strm) cptr() C.uintptr_t { return (C.uintptr_t)(x.id) }
  689. func getStrm(cptr uintptr) *strm {
  690. strms.mu.RLock()
  691. x := strms.m[int(cptr)]
  692. strms.mu.RUnlock()
  693. return x
  694. }
  695. //export go_strm_w_tramp
  696. func go_strm_w_tramp(pOut uintptr, pData *C.char, n C.int) C.int {
  697. //println("go_strm_w_tramp start")
  698. x := getStrm(pOut)
  699. b := (*[1 << 30]byte)(unsafe.Pointer(pData))[:n:n]
  700. for len(b) > 0 {
  701. nw, err := x.w.Write(b)
  702. x.n += nw
  703. b = b[nw:]
  704. if err != nil {
  705. if code := ErrCode(err); code != SQLITE_ERROR {
  706. return C.int(code)
  707. }
  708. return C.SQLITE_IOERR
  709. }
  710. }
  711. //println("go_strm_w_tramp OK, nw=", nw)
  712. return C.SQLITE_OK
  713. }
  714. //export go_strm_r_tramp
  715. func go_strm_r_tramp(pIn uintptr, pData *C.char, pnData *C.int) C.int {
  716. x := getStrm(pIn)
  717. b := (*[1 << 30]byte)(unsafe.Pointer(pData))[:*pnData:*pnData]
  718. var n int
  719. var err error
  720. for n == 0 && err == nil {
  721. // Technically an io.Reader is allowed to return (0, nil)
  722. // and it is not treated as the end of the stream.
  723. //
  724. // So we spin here until the io.Reader is gracious enough
  725. // to get off its butt and actually do something.
  726. n, err = x.r.Read(b)
  727. }
  728. x.n += n
  729. //println("*pnData:", *pnData, "n:", n)
  730. *pnData = C.int(n)
  731. if err != nil && err != io.EOF {
  732. if code := ErrCode(err); code != SQLITE_ERROR {
  733. return C.int(code)
  734. }
  735. return C.SQLITE_IOERR
  736. }
  737. return C.SQLITE_OK
  738. }
  739. type xapply struct {
  740. id int
  741. conn *Conn
  742. filterFn func(string) bool
  743. conflictFn func(ConflictType, ChangesetIter) ConflictAction
  744. }
  745. var xapplys = struct {
  746. mu sync.RWMutex
  747. m map[int]*xapply
  748. next int
  749. }{
  750. m: make(map[int]*xapply),
  751. }
  752. //export go_xapply_filter_tramp
  753. func go_xapply_filter_tramp(pCtx uintptr, zTab *C.char) C.int {
  754. xapplys.mu.Lock()
  755. x, ok := xapplys.m[int(pCtx)]
  756. xapplys.mu.Unlock()
  757. if !ok {
  758. panic("not ok")
  759. }
  760. if x == nil {
  761. panic("x == nil")
  762. }
  763. tableName := C.GoString(zTab)
  764. if x.filterFn(tableName) {
  765. return 1
  766. }
  767. return 0
  768. }
  769. //export go_xapply_conflict_tramp
  770. func go_xapply_conflict_tramp(pCtx uintptr, eConflict C.int, p *C.sqlite3_changeset_iter) C.int {
  771. xapplys.mu.Lock()
  772. x := xapplys.m[int(pCtx)]
  773. xapplys.mu.Unlock()
  774. action := x.conflictFn(ConflictType(eConflict), ChangesetIter{ptr: p})
  775. return C.int(action)
  776. }