@@ -55,56 +55,64 @@ function scalarfunc(expr::Expr)
55
55
return scalarfunc (f)
56
56
end
57
57
58
- # convert a byteptr to an int, ptr[start] -> 256^0, ptr[start+1] -> 256^1...
59
- # TODO : this assumes little-endian
58
+ # convert a byteptr to an int, assumes little-endian
60
59
function bytestoint (ptr:: Ptr{UInt8} , start:: Int , len:: Int )
61
60
s = 0
62
61
for i in start: start+ len- 1
63
62
v = unsafe_load (ptr, i)
64
63
s += v * 256 ^ (i - start)
65
64
end
66
65
67
- return s
66
+ # swap byte-order on big-endian machines
67
+ # TODO : this desperately needs testing on a big-endian machine!!!!!
68
+ return htol (s)
68
69
end
69
70
70
71
function stepfunc (init, func, fsym= symbol (string (func)* " _step" ))
71
72
nm = isdefined (Base,fsym) ? :(Base.$ fsym) : fsym
72
73
return quote
73
74
function $ (nm)(context:: Ptr{Void} , nargs:: Cint , values:: Ptr{Ptr{Void}} )
74
75
args = [sqlvalue (values, i) for i in 1 : nargs]
76
+
75
77
intsize = sizeof (Int)
76
78
ptrsize = sizeof (Ptr)
77
79
acsize = intsize + ptrsize
78
80
acptr = convert (Ptr{UInt8}, sqlite3_aggregate_context (context, acsize))
81
+
79
82
# acptr will be zeroed-out if this is the first iteration
80
83
ret = ccall (
81
84
:memcmp , Cint, (Ptr{UInt8}, Ptr{UInt8}, Cuint),
82
85
zeros (UInt8, acsize), acptr, acsize,
83
86
)
87
+ if ret == 0
88
+ acval = $ (init)
89
+ valsize = 256
90
+ # avoid the garbage collector using malloc
91
+ valptr = convert (Ptr{UInt8}, c_malloc (valsize))
92
+ else
93
+ # size of serialized value is first sizeof(Int) bytes
94
+ valsize = bytestoint (acptr, 1 , intsize)
95
+ # ptr to serialized value is last sizeof(Ptr) bytes
96
+ valptr = reinterpret (
97
+ Ptr{UInt8}, bytestoint (acptr, intsize+ 1 , ptrsize)
98
+ )
99
+ # deserialize the value pointed to by valptr
100
+ acvalbuf = zeros (UInt8, valsize)
101
+ unsafe_copy! (pointer (acvalbuf), valptr, valsize)
102
+ acval = sqldeserialize (acvalbuf)
103
+ end
104
+
84
105
try
85
- if ret == 0
86
- acval = $ (init)
87
- # TODO : allocate 256 byte
88
- valsize = sizeof (sqlserialize (acval))
89
- valptr = convert (Ptr{UInt8}, c_malloc (valsize))
90
- else
91
- # size of serialized value is first sizeof(Int) bytes
92
- valsize = bytestoint (acptr, 1 , intsize)
93
- # ptr to serialized value is last sizeof(Ptr) bytes
94
- valptr = reinterpret (
95
- Ptr{UInt8}, bytestoint (acptr, intsize+ 1 , ptrsize)
96
- )
97
- # deserialize the value pointed to by valptr
98
- acvalbuf = zeros (UInt8, valsize)
99
- unsafe_copy! (pointer (acvalbuf), valptr, valsize)
100
- acval = sqldeserialize (acvalbuf)
101
- end
102
106
funcret = sqlserialize ($ (func)(acval, args... ))
103
- newsize = length (funcret)
104
- # TODO : increase this in a cleverer way?
105
- newsize > valsize && (valptr = convert (Ptr{UInt8}, c_realloc (valptr, newsize)))
107
+
108
+ newsize = sizeof (funcret)
109
+ if newsize > valsize
110
+ # TODO : increase this in a cleverer way?
111
+ valptr = convert (Ptr{UInt8}, c_realloc (valptr, newsize))
112
+ end
106
113
# copy serialized return value
107
114
unsafe_copy! (valptr, pointer (funcret), newsize)
115
+
108
116
# following copies are easier with arrays
109
117
acptr = pointer_to_array (acptr, acsize, false )
110
118
# copy the size of the serialized value
@@ -133,33 +141,38 @@ function stepfunc(init, func, fsym=symbol(string(func)*"_step"))
133
141
end
134
142
end
135
143
136
- # TODO : free valptr on error
137
144
function finalfunc (init, func, fsym= symbol (string (func)* " _final" ))
138
145
nm = isdefined (Base,fsym) ? :(Base.$ fsym) : fsym
139
146
return quote
140
147
function $ (nm)(context:: Ptr{Void} , nargs:: Cint , values:: Ptr{Ptr{Void}} )
141
148
acptr = convert (Ptr{UInt8}, sqlite3_aggregate_context (context, 0 ))
149
+
142
150
# step function wasn't run
143
151
if acptr == C_NULL
144
152
sqlreturn (context, $ (init))
145
153
else
146
154
intsize = sizeof (Int)
147
155
ptrsize = sizeof (Ptr)
148
156
acsize = intsize + ptrsize
157
+
149
158
# load size
150
159
valsize = bytestoint (acptr, 1 , intsize)
151
160
# load ptr
152
161
valptr = reinterpret (
153
162
Ptr{UInt8}, bytestoint (acptr, intsize+ 1 , ptrsize)
154
163
)
155
- # load value
156
- acvalbuf = zeros (UInt8, valsize)
157
- unsafe_copy! (pointer (acvalbuf), valptr, valsize)
158
- acval = sqldeserialize (acvalbuf)
159
164
160
- ret = $ (func)(acval)
161
- c_free (valptr)
162
- sqlreturn (context, ret)
165
+ try
166
+ # load value
167
+ acvalbuf = zeros (UInt8, valsize)
168
+ unsafe_copy! (pointer (acvalbuf), valptr, valsize)
169
+ acval = sqldeserialize (acvalbuf)
170
+
171
+ ret = $ (func)(acval)
172
+ sqlreturn (context, ret)
173
+ finally
174
+ c_free (valptr)
175
+ end
163
176
end
164
177
nothing
165
178
end
0 commit comments