Skip to content

Commit cdf5f66

Browse files
committed
First version of implementation
1 parent ace7977 commit cdf5f66

File tree

2 files changed

+126
-31
lines changed

2 files changed

+126
-31
lines changed

sqlite3.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ package sqlite3
2727
#cgo CFLAGS: -DSQLITE_ENABLE_DBSTAT_VTAB
2828
#cgo CFLAGS: -DSQLITE_MEMDB_DEFAULT_MAXSIZE=2147483648
2929
#cgo CFLAGS: -DSQLITE_ENABLE_GEOPOLY=1
30+
#cgo CFLAGS: -DSQLITE_ENABLE_SESSION
31+
#cgo CFLAGS: -DSQLITE_ENABLE_PREUPDATE_HOOK
3032
#cgo CFLAGS: -Wno-deprecated-declarations
3133
#cgo openbsd CFLAGS: -I/usr/local/include
3234
#cgo openbsd LDFLAGS: -L/usr/local/lib

sqlite3_session.go

Lines changed: 124 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -15,60 +15,153 @@ package sqlite3
1515
#include <sqlite3.h>
1616
#endif
1717
#include <stdlib.h>
18+
#include <stdint.h>
1819
*/
1920
import "C"
21+
import (
22+
"fmt"
23+
"unsafe"
24+
)
25+
26+
type Session struct {
27+
session *C.sqlite3_session
28+
}
29+
30+
type Changeset struct {
31+
changeset *C.sqlite3_changeset_iter
32+
}
2033

2134
// CreateSession creates a new session object.
22-
func (c *SQLiteConn) CreateSession() error {
23-
return nil
35+
func (c *SQLiteConn) CreateSession(dbName string) (*Session, error) {
36+
cDbName := C.CString(dbName)
37+
defer C.free(unsafe.Pointer(cDbName))
38+
39+
var session *C.sqlite3_session
40+
rc := C.sqlite3session_create(c.db, cDbName, &session)
41+
if rc != C.SQLITE_OK {
42+
return nil, fmt.Errorf("sqlite3session_create: %s", C.GoString(C.sqlite3_errstr(rc)))
43+
}
44+
return &Session{session: session}, nil
2445
}
2546

26-
// AttachSession attaches a session object to a set of tables.
27-
func (c *SQLiteConn) AttachSession() error {
47+
// AttachSession attaches a session object to a table or all tables.
48+
func (s *Session) AttachSession(tableName string) error {
49+
var cTableName *C.char
50+
if tableName != "" {
51+
cTableName = C.CString(tableName)
52+
defer C.free(unsafe.Pointer(cTableName))
53+
}
54+
55+
rc := C.sqlite3session_attach(s.session, cTableName)
56+
if rc != C.SQLITE_OK {
57+
return fmt.Errorf("sqlite3session_attach: %s", C.GoString(C.sqlite3_errstr(rc)))
58+
}
2859
return nil
2960
}
3061

31-
// DetachSession deletes a session object.
32-
func (c *SQLiteConn) DeleteSession() error {
62+
// Delete deletes a session object.
63+
func (s *Session) DeleteSession() error {
64+
if s.session != nil {
65+
// Call sqlite3session_delete to free the session object
66+
C.sqlite3session_delete(s.session)
67+
s.session = nil // Set session to nil to avoid double deletion
68+
}
3369
return nil
3470
}
3571

36-
// SessionChangeset generates a changeset from a session object.
37-
func (c *SQLiteConn) Changeset() error {
38-
return nil
72+
type ChangesetIter struct {
73+
iter *C.sqlite3_changeset_iter
3974
}
4075

41-
// ChangesetStart is called to create and initialize an iterator
42-
// to iterate through the contents of a changeset. Initially, the
43-
// iterator points to no element at all
44-
func (c *SQLiteConn) ChangesetStart() error {
45-
return nil
76+
// Changeset generates a changeset from a session object.
77+
func (s *Session) Changeset() ([]byte, error) {
78+
var nChangeset C.int
79+
var pChangeset unsafe.Pointer
80+
81+
// Call sqlite3session_changeset
82+
rc := C.sqlite3session_changeset(s.session, &nChangeset, &pChangeset)
83+
if rc != C.SQLITE_OK {
84+
return nil, fmt.Errorf("sqlite3session_changeset: %s", C.GoString(C.sqlite3_errstr(rc)))
85+
}
86+
defer C.sqlite3_free(pChangeset) // Free the changeset buffer after use
87+
88+
// Convert the C buffer to a Go byte slice
89+
changeset := C.GoBytes(pChangeset, nChangeset)
90+
return changeset, nil
4691
}
4792

48-
// ChangesetNext moves a Changeset iterator to the next change in the
49-
// changeset.
50-
func (c *SQLiteConn) ChangesetNext() error {
51-
return nil
93+
// ChangesetStart creates and initializes a changeset iterator.
94+
func ChangesetStart(changeset []byte) (*ChangesetIter, error) {
95+
var iter *C.sqlite3_changeset_iter
96+
97+
// Call sqlite3changeset_start
98+
rc := C.sqlite3changeset_start(&iter, C.int(len(changeset)), unsafe.Pointer(&changeset[0]))
99+
if rc != C.SQLITE_OK {
100+
return nil, fmt.Errorf("sqlite3changeset_start: %s", C.GoString(C.sqlite3_errstr(rc)))
101+
}
102+
103+
return &ChangesetIter{iter: iter}, nil
52104
}
53105

54-
// ChangesetOp retuns the type of change (INSERT, UPDATE or DELETE)
55-
// that the iterator points to
56-
func (c *SQLiteConn) ChangesetOp() error {
57-
return nil
106+
// ChangesetNext moves the changeset iterator to the next change.
107+
func (ci *ChangesetIter) ChangesetNext() (bool, error) {
108+
rc := C.sqlite3changeset_next(ci.iter)
109+
if rc == C.SQLITE_DONE {
110+
return false, nil // No more changes
111+
}
112+
if rc != C.SQLITE_OK {
113+
return false, fmt.Errorf("sqlite3changeset_next: %s", C.GoString(C.sqlite3_errstr(rc)))
114+
}
115+
return true, nil
58116
}
59117

60-
// ChangesetOld may be used to obtain the old.* values within the change payload.
61-
func (c *SQLiteConn) ChangesetOld() error {
62-
return nil
118+
// ChangesetOp returns the type of change (INSERT, UPDATE, or DELETE) that the iterator points to.
119+
func (ci *ChangesetIter) ChangesetOp() (string, int, int, bool, error) {
120+
var tableName *C.char
121+
var nCol C.int
122+
var op C.int
123+
var indirect C.int
124+
125+
rc := C.sqlite3changeset_op(ci.iter, &tableName, &nCol, &op, &indirect)
126+
if rc != C.SQLITE_OK {
127+
return "", 0, 0, false, fmt.Errorf("sqlite3changeset_op: %s", C.GoString(C.sqlite3_errstr(rc)))
128+
}
129+
130+
return C.GoString(tableName), int(nCol), int(op), indirect != 0, nil
63131
}
64132

65-
// ChangesetNew may be used to obtain the new.* values within the change payload.
66-
func (c *SQLiteConn) ChangesetNew() error {
67-
return nil
133+
// ChangesetOld retrieves the old value for the specified column in the change payload.
134+
func (ci *ChangesetIter) ChangesetOld(column int) (*C.sqlite3_value, error) {
135+
var value *C.sqlite3_value
136+
137+
rc := C.sqlite3changeset_old(ci.iter, C.int(column), &value)
138+
if rc != C.SQLITE_OK {
139+
return nil, fmt.Errorf("sqlite3changeset_old: %s", C.GoString(C.sqlite3_errstr(rc)))
140+
}
141+
142+
return value, nil
68143
}
69144

70-
// ChangesetFinalize is called to delete a changeste iterator.
71-
func (c *SQLiteConn) ChangesetFinalize() error {
72-
return nil
145+
// ChangesetNew retrieves the new value for the specified column in the change payload.
146+
func (ci *ChangesetIter) ChangesetNew(column int) (*C.sqlite3_value, error) {
147+
var value *C.sqlite3_value
148+
149+
rc := C.sqlite3changeset_new(ci.iter, C.int(column), &value)
150+
if rc != C.SQLITE_OK {
151+
return nil, fmt.Errorf("sqlite3changeset_new: %s", C.GoString(C.sqlite3_errstr(rc)))
152+
}
153+
154+
return value, nil
73155
}
74156

157+
// ChangesetFinalize deletes a changeset iterator.
158+
func (ci *ChangesetIter) ChangesetFinalize() error {
159+
if ci.iter != nil {
160+
rc := C.sqlite3changeset_finalize(ci.iter)
161+
ci.iter = nil // Prevent double finalization
162+
if rc != C.SQLITE_OK {
163+
return fmt.Errorf("sqlite3changeset_finalize: %s", C.GoString(C.sqlite3_errstr(rc)))
164+
}
165+
}
166+
return nil
167+
}

0 commit comments

Comments
 (0)