Skip to content

Commit 7db8ef2

Browse files
committed
Merge branch 'master' of git://github.com/quinnj/SQLite.jl
2 parents 8468df0 + 5ee41db commit 7db8ef2

File tree

6 files changed

+106
-116
lines changed

6 files changed

+106
-116
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ A Julia interface to the SQLite library and support for operations on DataFrames
5959

6060
An SQL statement `sql` is prepared, executed in the context of `db`, and results, if any, are returned. The return values are a `(String[],Any[])` tuple representing `(column names, result values)`.
6161

62-
The values in `values` are used in parameter binding (see `bind` above). If your statement uses nameless parameters `values` must be a Vector of the values you wish to bind to your statment. If your statement uses named parameters `values` must be a Dict where the keys are of type String or Symbol. The key must match an identifier name in the statement (the name **does not** include the ':', '@' or '$' prefix). You can not use a dictionary which has Strings *and* Symbols for it's keys.
62+
The values in `values` are used in parameter binding (see `bind` above). If your statement uses nameless parameters `values` must be a `Vector` of the values you wish to bind to your statment. If your statement uses named parameters `values` must be a Dict where the keys are of type `Symbol`. The key must match an identifier name in the statement (the name **does not** include the ':', '@' or '$' prefix).
6363

6464
* `create(db::SQLiteDB,name::String,table::AbstractMatrix,
6565
colnames=String[],coltypes=DataType[];temp::Bool=false)`

src/SQLite.jl

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ export NULL, SQLiteDB, SQLiteStmt, ResultSet,
44
execute, query, tables, drop, create, append
55

66
type SQLiteException <: Exception
7-
msg::String
7+
msg::AbstractString
88
end
99

1010
include("consts.jl")
@@ -23,15 +23,15 @@ end
2323
==(a::ResultSet,b::ResultSet) = a.colnames == b.colnames && a.values == b.values
2424
include("show.jl")
2525

26-
type SQLiteDB{T<:String}
26+
type SQLiteDB{T<:AbstractString}
2727
file::T
2828
handle::Ptr{Void}
2929
changes::Int
3030
end
3131
SQLiteDB(file,handle) = SQLiteDB(file,handle,0)
3232

3333
include("UDF.jl")
34-
export registerfunc, sqlreturn, @scalarfunc, @sr_str
34+
export @sr_str, @register, register
3535

3636

3737
function changes(db::SQLiteDB)
@@ -48,13 +48,13 @@ sqliteopen(file::UTF16String,handle) = sqlite3_open16(file,handle)
4848
sqliteerror() = throw(SQLiteException(bytestring(sqlite3_errmsg())))
4949
sqliteerror(db) = throw(SQLiteException(bytestring(sqlite3_errmsg(db.handle))))
5050

51-
function SQLiteDB(file::String="";UTF16::Bool=false)
51+
function SQLiteDB(file::AbstractString="";UTF16::Bool=false)
5252
handle = [C_NULL]
5353
utf = UTF16 ? utf16 : utf8
5454
file = isempty(file) ? file : expanduser(file)
5555
if @OK sqliteopen(utf(file),handle)
5656
db = SQLiteDB(utf(file),handle[1])
57-
registerfunc(db, 2, regexp)
57+
register(db, regexp, nargs=2)
5858
finalizer(db,close)
5959
return db
6060
else # error
@@ -83,7 +83,7 @@ sqliteprepare(db,sql,stmt,null) =
8383
sqliteprepare(db::SQLiteDB{UTF16String},sql,stmt,null) =
8484
@CHECK db sqlite3_prepare16_v2(db.handle,utf16(sql),stmt,null)
8585

86-
function SQLiteStmt{T}(db::SQLiteDB{T},sql::String)
86+
function SQLiteStmt{T}(db::SQLiteDB{T},sql::AbstractString)
8787
handle = [C_NULL]
8888
sqliteprepare(db,sql,handle,[C_NULL])
8989
stmt = SQLiteStmt(db,handle[1],convert(T,sql))
@@ -112,26 +112,26 @@ function Base.bind{V}(stmt::SQLiteStmt, values::Dict{Symbol, V})
112112
@assert nparams == length(values) "you must provide values for all placeholders"
113113
for i in 1:nparams
114114
name = bytestring(sqlite3_bind_parameter_name(stmt.handle, i))
115-
@assert !isempty(name) "nameless parameters should be passed as a tuple"
115+
@assert !isempty(name) "nameless parameters should be passed as a Vector"
116116
# name is returned with the ':', '@' or '$' at the start
117117
name = name[2:end]
118118
bind(stmt, i, values[symbol(name)])
119119
end
120120
end
121121
# Binding parameters to SQL statements
122-
function Base.bind(stmt::SQLiteStmt,name::String,val)
122+
function Base.bind(stmt::SQLiteStmt,name::AbstractString,val)
123123
i = sqlite3_bind_parameter_index(stmt.handle,name)
124124
if i == 0
125125
throw(SQLiteException("SQL parameter $name not found in $stmt"))
126126
end
127127
return bind(stmt,i,val)
128128
end
129-
Base.bind(stmt::SQLiteStmt,i::Int,val::FloatingPoint) = @CHECK stmt.db sqlite3_bind_double(stmt.handle,i,float64(val))
130-
Base.bind(stmt::SQLiteStmt,i::Int,val::Int32) = @CHECK stmt.db sqlite3_bind_int(stmt.handle,i,val)
131-
Base.bind(stmt::SQLiteStmt,i::Int,val::Int64) = @CHECK stmt.db sqlite3_bind_int64(stmt.handle,i,val)
132-
Base.bind(stmt::SQLiteStmt,i::Int,val::NullType) = @CHECK stmt.db sqlite3_bind_null(stmt.handle,i)
133-
Base.bind(stmt::SQLiteStmt,i::Int,val::String) = @CHECK stmt.db sqlite3_bind_text(stmt.handle,i,val)
134-
Base.bind(stmt::SQLiteStmt,i::Int,val::UTF16String) = @CHECK stmt.db sqlite3_bind_text16(stmt.handle,i,val)
129+
Base.bind(stmt::SQLiteStmt,i::Int,val::FloatingPoint) = @CHECK stmt.db sqlite3_bind_double(stmt.handle,i,float64(val))
130+
Base.bind(stmt::SQLiteStmt,i::Int,val::Int32) = @CHECK stmt.db sqlite3_bind_int(stmt.handle,i,val)
131+
Base.bind(stmt::SQLiteStmt,i::Int,val::Int64) = @CHECK stmt.db sqlite3_bind_int64(stmt.handle,i,val)
132+
Base.bind(stmt::SQLiteStmt,i::Int,val::NullType) = @CHECK stmt.db sqlite3_bind_null(stmt.handle,i)
133+
Base.bind(stmt::SQLiteStmt,i::Int,val::AbstractString) = @CHECK stmt.db sqlite3_bind_text(stmt.handle,i,val)
134+
Base.bind(stmt::SQLiteStmt,i::Int,val::UTF16String) = @CHECK stmt.db sqlite3_bind_text16(stmt.handle,i,val)
135135
# Fallback is BLOB and defaults to serializing the julia value
136136
function sqlserialize(x)
137137
t = IOBuffer()
@@ -153,23 +153,23 @@ function execute(stmt::SQLiteStmt)
153153
end
154154
return r
155155
end
156-
function execute(db::SQLiteDB,sql::String)
156+
function execute(db::SQLiteDB,sql::AbstractString)
157157
stmt = SQLiteStmt(db,sql)
158158
execute(stmt)
159159
return changes(db)
160160
end
161161

162162
sqldeserialize(r) = deserialize(IOBuffer(r))
163163

164-
function query(db::SQLiteDB,sql::String, values=[])
164+
function query(db::SQLiteDB,sql::AbstractString, values=[])
165165
stmt = SQLiteStmt(db,sql)
166166
bind(stmt, values)
167167
status = execute(stmt)
168168
ncols = sqlite3_column_count(stmt.handle)
169169
if status == SQLITE_DONE || ncols == 0
170170
return changes(db)
171171
end
172-
colnames = Array(String,ncols)
172+
colnames = Array(AbstractString,ncols)
173173
results = Array(Any,ncols)
174174
for i = 1:ncols
175175
colnames[i] = bytestring(sqlite3_column_name(stmt.handle,i-1))
@@ -220,7 +220,7 @@ function transaction(db, mode="DEFERRED")
220220
221221
If mode is one of "", "DEFERRED", "IMMEDIATE" or "EXCLUSIVE" then a
222222
transaction of that (or the default) type is started. Otherwise a savepoint
223-
is created whose name is mode converted to String.
223+
is created whose name is mode converted to AbstractString.
224224
=#
225225
if uppercase(mode) in ["", "DEFERRED", "IMMEDIATE", "EXCLUSIVE"]
226226
execute(db, "BEGIN $(mode) TRANSACTION;")
@@ -257,15 +257,15 @@ commit(db, name) = execute(db, "RELEASE SAVEPOINT $(name);")
257257
rollback(db) = execute(db, "ROLLBACK TRANSACTION;")
258258
rollback(db, name) = execute(db, "ROLLBACK TRANSACTION TO SAVEPOINT $(name);")
259259

260-
function drop(db::SQLiteDB,table::String)
260+
function drop(db::SQLiteDB,table::AbstractString)
261261
transaction(db) do
262262
execute(db,"drop table $table")
263263
end
264264
execute(db,"vacuum")
265265
return changes(db)
266266
end
267267

268-
function dropindex(db::SQLiteDB,index::String)
268+
function dropindex(db::SQLiteDB,index::AbstractString)
269269
transaction(db) do
270270
execute(db,"drop index $index")
271271
end
@@ -274,12 +274,12 @@ end
274274

275275
gettype{T<:Integer}(::Type{T}) = " INT"
276276
gettype{T<:Real}(::Type{T}) = " REAL"
277-
gettype{T<:String}(::Type{T}) = " TEXT"
277+
gettype{T<:AbstractString}(::Type{T}) = " TEXT"
278278
gettype(::Type) = " BLOB"
279279
gettype(::Type{NullType}) = " NULL"
280280

281-
function create(db::SQLiteDB,name::String,table,
282-
colnames=String[],coltypes=DataType[];temp::Bool=false)
281+
function create(db::SQLiteDB,name::AbstractString,table,
282+
colnames=AbstractString[],coltypes=DataType[];temp::Bool=false)
283283
N, M = size(table)
284284
colnames = isempty(colnames) ? ["x$i" for i=1:M] : colnames
285285
coltypes = isempty(coltypes) ? [typeof(table[1,i]) for i=1:M] : coltypes
@@ -305,7 +305,7 @@ function create(db::SQLiteDB,name::String,table,
305305
return changes(db)
306306
end
307307

308-
function createindex(db::SQLiteDB,table::String,index::String,cols;unique::Bool=true)
308+
function createindex(db::SQLiteDB,table::AbstractString,index::AbstractString,cols;unique::Bool=true)
309309
u = unique ? "unique" : ""
310310
transaction(db) do
311311
execute(db,"create $u index $index on $table ($cols)")
@@ -314,7 +314,7 @@ function createindex(db::SQLiteDB,table::String,index::String,cols;unique::Bool=
314314
return changes(db)
315315
end
316316

317-
function append(db::SQLiteDB,name::String,table)
317+
function append(db::SQLiteDB,name::AbstractString,table)
318318
N, M = size(table)
319319
transaction(db) do
320320
# insert statements
@@ -333,7 +333,7 @@ function append(db::SQLiteDB,name::String,table)
333333
return return changes(db)
334334
end
335335

336-
function deleteduplicates(db,table::String,cols::String)
336+
function deleteduplicates(db,table::AbstractString,cols::AbstractString)
337337
transaction(db) do
338338
execute(db,"delete from $table where rowid not in (select max(rowid) from $table group by $cols);")
339339
end

src/UDF.jl

Lines changed: 44 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,3 @@
1-
# scalar functions
2-
function registerfunc(db::SQLiteDB, nargs::Integer, func::Function, isdeterm::Bool=true; name="")
3-
@assert nargs <= 127 "only varargs functions can have more than 127 arguments"
4-
# assume any negative number means a varargs function
5-
nargs < -1 && (nargs = -1)
6-
7-
name = isempty(name) ? string(func) : name::String
8-
@assert sizeof(name) <= 255 "size of function name must be <= 255"
9-
10-
cfunc = cfunction(func, Nothing, (Ptr{Void}, Cint, Ptr{Ptr{Void}}))
11-
12-
# TODO: allow the other encodings
13-
enc = SQLITE_UTF8
14-
enc = isdeterm ? enc | SQLITE_DETERMINISTIC : enc
15-
16-
@CHECK db sqlite3_create_function_v2(
17-
db.handle, name, nargs, enc, C_NULL, cfunc, C_NULL, C_NULL, C_NULL
18-
)
19-
end
20-
21-
# aggregate functions
22-
function registerfunc(db::SQLiteDB, nargs::Integer, step::Function, final::Function, isdeterm::Bool=true; name="")
23-
@assert nargs <= 127 "only varargs functions can have more than 127 arguments"
24-
# assume any negative number means a varargs function
25-
nargs < -1 && (nargs = -1)
26-
27-
name = isempty(name) ? string(step) : name::String
28-
cstep = cfunction(step, Nothing, (Ptr{Void}, Cint, Ptr{Ptr{Void}}))
29-
cfinal = cfunction(final, Nothing, (Ptr{Void}, Cint, Ptr{Ptr{Void}}))
30-
31-
# TODO: allow the other encodings
32-
enc = SQLITE_UTF8
33-
enc = isdeterm ? enc | SQLITE_DETERMINISTIC : enc
34-
35-
@CHECK db sqlite3_create_function_v2(
36-
db.handle, name, nargs, enc, C_NULL, C_NULL, cstep, cfinal, C_NULL
37-
)
38-
end
39-
401
function sqlvalue(values, i)
412
temp_val_ptr = unsafe_load(values, i)
423
valuetype = sqlite3_value_type(temp_val_ptr)
@@ -63,43 +24,60 @@ function sqlvalue(values, i)
6324
end
6425
end
6526

66-
sqlreturn(context, ::NullType) = sqlite3_result_null(context)
67-
sqlreturn(context, val::Int32) = sqlite3_result_int(context, val)
68-
sqlreturn(context, val::Int64) = sqlite3_result_int64(context, val)
69-
sqlreturn(context, val::Float64) = sqlite3_result_double(context, val)
70-
sqlreturn(context, val::String) = sqlite3_result_text(context, val)
71-
sqlreturn(context, val::UTF16String) = sqlite3_result_text16(context, val)
72-
sqlreturn(context, val) = sqlite3_result_blob(context, sqlserialize(val))
27+
sqlreturn(context, ::NullType) = sqlite3_result_null(context)
28+
sqlreturn(context, val::Int32) = sqlite3_result_int(context, val)
29+
sqlreturn(context, val::Int64) = sqlite3_result_int64(context, val)
30+
sqlreturn(context, val::Float64) = sqlite3_result_double(context, val)
31+
sqlreturn(context, val::UTF16String) = sqlite3_result_text16(context, val)
32+
sqlreturn(context, val::AbstractString) = sqlite3_result_text(context, val)
33+
sqlreturn(context, val) = sqlite3_result_blob(context, sqlserialize(val))
7334

7435
sqlreturn(context, val::Bool) = sqlreturn(context, int(val))
7536

76-
sqludferror(context, msg::String) = sqlite3_result_error(context, msg)
77-
sqludferror(context, msg::UTF16String) = sqlite3_result_error16(context, msg)
78-
79-
function funcname(expr)
80-
if length(expr) == 2
81-
func = expr[2]
82-
name = expr[1]
83-
else
84-
func = expr[1]
85-
name = func.args[1].args[1]
86-
end
87-
name, func
88-
end
89-
90-
macro scalarfunc(args...)
91-
name, func = funcname(args)
37+
# Internal method for generating an SQLite scalar function from
38+
# a Julia function name
39+
function scalarfunc(func,fsym=symbol(string(func)))
40+
# check if name defined in Base so we don't clobber Base methods
41+
nm = isdefined(Base,fsym) ? :(Base.$fsym) : fsym
9242
return quote
93-
function $(esc(name))(context::Ptr{Void}, nargs::Cint, values::Ptr{Ptr{Void}})
94-
args = [sqlvalue(values, i) for i in 1:nargs]
43+
#nm needs to be a symbol or expr, i.e. :sin or :(Base.sin)
44+
function $(nm)(context::Ptr{Void}, nargs::Cint, values::Ptr{Ptr{Void}})
45+
args = [SQLite.sqlvalue(values, i) for i in 1:nargs]
9546
ret = $(func)(args...)
96-
sqlreturn(context, ret)
47+
SQLite.sqlreturn(context, ret)
9748
nothing
9849
end
9950
end
10051
end
52+
function scalarfunc(expr::Expr)
53+
f = eval(expr)
54+
return scalarfunc(f)
55+
end
56+
# User-facing macro for convenience in registering a simple function
57+
# with no configurations needed
58+
macro register(db, func)
59+
:(register($(esc(db)), $(esc(func))))
60+
end
61+
# User-facing method for registering a Julia function to be used within SQLite
62+
function register(db::SQLiteDB, func::Function; nargs::Int=-1, name::AbstractString=string(func), isdeterm::Bool=true)
63+
@assert nargs <= 127 "use -1 if > 127 arguments are needed"
64+
# assume any negative number means a varargs function
65+
nargs < -1 && (nargs = -1)
66+
@assert sizeof(name) <= 255 "size of function name must be <= 255"
67+
68+
f = eval(scalarfunc(func,symbol(name)))
69+
70+
cfunc = cfunction(f, Nothing, (Ptr{Void}, Cint, Ptr{Ptr{Void}}))
71+
# TODO: allow the other encodings
72+
enc = SQLITE_UTF8
73+
enc = isdeterm ? enc | SQLITE_DETERMINISTIC : enc
74+
75+
@CHECK db sqlite3_create_function_v2(
76+
db.handle, name, nargs, enc, C_NULL, cfunc, C_NULL, C_NULL, C_NULL
77+
)
78+
end
10179

10280
# annotate types because the MethodError makes more sense that way
103-
@scalarfunc regexp(r::String, s::String) = ismatch(Regex(r), s)
81+
regexp(r::AbstractString, s::AbstractString) = ismatch(Regex(r), s)
10482
# macro for preserving the special characters in a string
10583
macro sr_str(s) s end

0 commit comments

Comments
 (0)