Skip to content

Commit 0e420d3

Browse files
committed
Merge branch 'master' into quinnj-jq/scalarfuncs
Conflicts: src/UDF.jl
2 parents 2af4c4f + 72430bb commit 0e420d3

File tree

6 files changed

+109
-50
lines changed

6 files changed

+109
-50
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ A Julia interface to the SQLite library and support for operations on DataFrames
5555

5656
Used to execute prepared `SQLiteStmt`. The 2nd method is a convenience method to pass in an SQL statement as a string which gets prepared and executed in one call. This method does not check for or return any results, hence it is only useful for database manipulation methods (i.e. ALTER, CREATE, UPDATE, DROP). To return results, see `query` below. Also consider the `create`, `drop`, and `append` methods for manipulation statements as further SQLite performance tricks are incorporated automatically.
5757

58-
* `query(db::SQLiteDB, sql::String)`
58+
* `query(db::SQLiteDB, sql::String, values=[])`
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 `Symbol`. The key must match an identifier name in the statement (the name **does not** include the ':', '@' or '$' prefix).
63+
6264
* `create(db::SQLiteDB,name::String,table::AbstractMatrix,
6365
colnames=String[],coltypes=DataType[];temp::Bool=false)`
6466

src/SQLite.jl

Lines changed: 44 additions & 23 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,7 +23,7 @@ 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
@@ -48,7 +48,7 @@ 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)
@@ -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))
@@ -98,20 +98,40 @@ function Base.close(stmt::SQLiteStmt)
9898
return
9999
end
100100

101+
# bind a row to nameless parameters
102+
function Base.bind(stmt::SQLiteStmt, values::Vector)
103+
nparams = sqlite3_bind_parameter_count(stmt.handle)
104+
@assert nparams == length(values) "you must provide values for all placeholders"
105+
for i in 1:nparams
106+
@inbounds bind(stmt, i, values[i])
107+
end
108+
end
109+
# bind a row to named parameters
110+
function Base.bind{V}(stmt::SQLiteStmt, values::Dict{Symbol, V})
111+
nparams = sqlite3_bind_parameter_count(stmt.handle)
112+
@assert nparams == length(values) "you must provide values for all placeholders"
113+
for i in 1:nparams
114+
name = bytestring(sqlite3_bind_parameter_name(stmt.handle, i))
115+
@assert !isempty(name) "nameless parameters should be passed as a Vector"
116+
# name is returned with the ':', '@' or '$' at the start
117+
name = name[2:end]
118+
bind(stmt, i, values[symbol(name)])
119+
end
120+
end
101121
# Binding parameters to SQL statements
102-
function Base.bind(stmt::SQLiteStmt,name::String,val)
122+
function Base.bind(stmt::SQLiteStmt,name::AbstractString,val)
103123
i = sqlite3_bind_parameter_index(stmt.handle,name)
104124
if i == 0
105125
throw(SQLiteException("SQL parameter $name not found in $stmt"))
106126
end
107127
return bind(stmt,i,val)
108128
end
109-
Base.bind(stmt::SQLiteStmt,i::Int,val::FloatingPoint) = @CHECK stmt.db sqlite3_bind_double(stmt.handle,i,float64(val))
110-
Base.bind(stmt::SQLiteStmt,i::Int,val::Int32) = @CHECK stmt.db sqlite3_bind_int(stmt.handle,i,val)
111-
Base.bind(stmt::SQLiteStmt,i::Int,val::Int64) = @CHECK stmt.db sqlite3_bind_int64(stmt.handle,i,val)
112-
Base.bind(stmt::SQLiteStmt,i::Int,val::NullType) = @CHECK stmt.db sqlite3_bind_null(stmt.handle,i)
113-
Base.bind(stmt::SQLiteStmt,i::Int,val::String) = @CHECK stmt.db sqlite3_bind_text(stmt.handle,i,val)
114-
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)
115135
# Fallback is BLOB and defaults to serializing the julia value
116136
function sqlserialize(x)
117137
t = IOBuffer()
@@ -133,22 +153,23 @@ function execute(stmt::SQLiteStmt)
133153
end
134154
return r
135155
end
136-
function execute(db::SQLiteDB,sql::String)
156+
function execute(db::SQLiteDB,sql::AbstractString)
137157
stmt = SQLiteStmt(db,sql)
138158
execute(stmt)
139159
return changes(db)
140160
end
141161

142162
sqldeserialize(r) = deserialize(IOBuffer(r))
143163

144-
function query(db::SQLiteDB,sql::String)
164+
function query(db::SQLiteDB,sql::AbstractString, values=[])
145165
stmt = SQLiteStmt(db,sql)
166+
bind(stmt, values)
146167
status = execute(stmt)
147168
ncols = sqlite3_column_count(stmt.handle)
148169
if status == SQLITE_DONE || ncols == 0
149170
return changes(db)
150171
end
151-
colnames = Array(String,ncols)
172+
colnames = Array(AbstractString,ncols)
152173
results = Array(Any,ncols)
153174
for i = 1:ncols
154175
colnames[i] = bytestring(sqlite3_column_name(stmt.handle,i-1))
@@ -199,7 +220,7 @@ function transaction(db, mode="DEFERRED")
199220
200221
If mode is one of "", "DEFERRED", "IMMEDIATE" or "EXCLUSIVE" then a
201222
transaction of that (or the default) type is started. Otherwise a savepoint
202-
is created whose name is mode converted to String.
223+
is created whose name is mode converted to AbstractString.
203224
=#
204225
if uppercase(mode) in ["", "DEFERRED", "IMMEDIATE", "EXCLUSIVE"]
205226
execute(db, "BEGIN $(mode) TRANSACTION;")
@@ -236,15 +257,15 @@ commit(db, name) = execute(db, "RELEASE SAVEPOINT $(name);")
236257
rollback(db) = execute(db, "ROLLBACK TRANSACTION;")
237258
rollback(db, name) = execute(db, "ROLLBACK TRANSACTION TO SAVEPOINT $(name);")
238259

239-
function drop(db::SQLiteDB,table::String)
260+
function drop(db::SQLiteDB,table::AbstractString)
240261
transaction(db) do
241262
execute(db,"drop table $table")
242263
end
243264
execute(db,"vacuum")
244265
return changes(db)
245266
end
246267

247-
function dropindex(db::SQLiteDB,index::String)
268+
function dropindex(db::SQLiteDB,index::AbstractString)
248269
transaction(db) do
249270
execute(db,"drop index $index")
250271
end
@@ -253,12 +274,12 @@ end
253274

254275
gettype{T<:Integer}(::Type{T}) = " INT"
255276
gettype{T<:Real}(::Type{T}) = " REAL"
256-
gettype{T<:String}(::Type{T}) = " TEXT"
277+
gettype{T<:AbstractString}(::Type{T}) = " TEXT"
257278
gettype(::Type) = " BLOB"
258279
gettype(::Type{NullType}) = " NULL"
259280

260-
function create(db::SQLiteDB,name::String,table,
261-
colnames=String[],coltypes=DataType[];temp::Bool=false)
281+
function create(db::SQLiteDB,name::AbstractString,table,
282+
colnames=AbstractString[],coltypes=DataType[];temp::Bool=false)
262283
N, M = size(table)
263284
colnames = isempty(colnames) ? ["x$i" for i=1:M] : colnames
264285
coltypes = isempty(coltypes) ? [typeof(table[1,i]) for i=1:M] : coltypes
@@ -284,7 +305,7 @@ function create(db::SQLiteDB,name::String,table,
284305
return changes(db)
285306
end
286307

287-
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)
288309
u = unique ? "unique" : ""
289310
transaction(db) do
290311
execute(db,"create $u index $index on $table ($cols)")
@@ -293,7 +314,7 @@ function createindex(db::SQLiteDB,table::String,index::String,cols;unique::Bool=
293314
return changes(db)
294315
end
295316

296-
function append(db::SQLiteDB,name::String,table)
317+
function append(db::SQLiteDB,name::AbstractString,table)
297318
N, M = size(table)
298319
transaction(db) do
299320
# insert statements
@@ -312,7 +333,7 @@ function append(db::SQLiteDB,name::String,table)
312333
return return changes(db)
313334
end
314335

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

src/UDF.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,17 @@ function sqlvalue(values, i)
2424
end
2525
end
2626

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::String) = sqlite3_result_text(context, val)
32-
sqlreturn(context, val::UTF16String) = sqlite3_result_text16(context, val)
33-
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))
3434

3535
sqlreturn(context, val::Bool) = sqlreturn(context, int(val))
3636

37-
sqludferror(context, msg::String) = sqlite3_result_error(context, msg)
37+
sqludferror(context, msg::AbstractString) = sqlite3_result_error(context, msg)
3838
sqludferror(context, msg::UTF16String) = sqlite3_result_error16(context, msg)
3939

4040
# Internal method for generating an SQLite scalar function from

src/api.jl

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function sqlite3_errmsg(db::Ptr{Void})
99
Ptr{Uint8}, (Ptr{Void},),
1010
db)
1111
end
12-
function sqlite3_open(file::String,handle::Array{Ptr{Void},1})
12+
function sqlite3_open(file::AbstractString,handle::Array{Ptr{Void},1})
1313
return ccall( (:sqlite3_open, sqlite3_lib),
1414
Cint, (Ptr{Uint8},Ptr{Void}),
1515
file,handle)
@@ -31,13 +31,13 @@ function sqlite3_next_stmt(db::Ptr{Void},stmt::Ptr{Void})
3131
Ptr{Void}, (Ptr{Void},Ptr{Void}),
3232
db, stmt)
3333
end
34-
function sqlite3_prepare_v2(handle::Ptr{Void},query::String,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
34+
function sqlite3_prepare_v2(handle::Ptr{Void},query::AbstractString,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
3535
@NULLCHECK handle
3636
return ccall( (:sqlite3_prepare_v2, sqlite3_lib),
3737
Cint, (Ptr{Void},Ptr{Uint8},Cint,Ptr{Void},Ptr{Void}),
3838
handle,query,sizeof(query),stmt,unused)
3939
end
40-
function sqlite3_prepare16_v2(handle::Ptr{Void},query::String,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
40+
function sqlite3_prepare16_v2(handle::Ptr{Void},query::AbstractString,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
4141
@NULLCHECK handle
4242
return ccall( (:sqlite3_prepare16_v2, sqlite3_lib),
4343
Cint, (Ptr{Void},Ptr{Uint16},Cint,Ptr{Void},Ptr{Void}),
@@ -49,8 +49,23 @@ function sqlite3_finalize(stmt::Ptr{Void})
4949
Cint, (Ptr{Void},),
5050
stmt)
5151
end
52+
53+
# SQLITE_API int sqlite3_bind_paramter_count(sqlite3_stmt*)
54+
function sqlite3_bind_parameter_count(stmt::Ptr{Void})
55+
@NULLCHECK stmt
56+
return ccall( (:sqlite3_bind_parameter_count, sqlite3_lib),
57+
Cint, (Ptr{Void},),
58+
stmt)
59+
end
60+
#SQLITE_API const char* sqlite3_bind_parameter_name(sqlite3_stmt*, int)
61+
function sqlite3_bind_parameter_name(stmt::Ptr{Void}, col::Int)
62+
@NULLCHECK stmt
63+
return ccall( (:sqlite3_bind_parameter_name, sqlite3_lib),
64+
Ptr{Uint8}, (Ptr{Void}, Cint),
65+
stmt, col)
66+
end
5267
# SQLITE_API int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName);
53-
function sqlite3_bind_parameter_index(stmt::Ptr{Void},value::String)
68+
function sqlite3_bind_parameter_index(stmt::Ptr{Void},value::AbstractString)
5469
@NULLCHECK stmt
5570
return ccall( (:sqlite3_bind_parameter_index, sqlite3_lib),
5671
Cint, (Ptr{Void},Ptr{Uint8}),
@@ -85,7 +100,7 @@ function sqlite3_bind_null(stmt::Ptr{Void},col::Int)
85100
stmt,col)
86101
end
87102
# SQLITE_API int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*));
88-
function sqlite3_bind_text(stmt::Ptr{Void},col::Int,value::String)
103+
function sqlite3_bind_text(stmt::Ptr{Void},col::Int,value::AbstractString)
89104
@NULLCHECK stmt
90105
return ccall( (:sqlite3_bind_text, sqlite3_lib),
91106
Cint, (Ptr{Void},Cint,Ptr{Uint8},Cint,Ptr{Void}),
@@ -108,8 +123,6 @@ end
108123
# SQLITE_API int sqlite3_bind_zeroblob(sqlite3_stmt*, int, int n);
109124
# SQLITE_API int sqlite3_bind_value(sqlite3_stmt*, int, const sqlite3_value*);
110125

111-
# SQLITE_API int sqlite3_bind_parameter_count(sqlite3_stmt*);
112-
# SQLITE_API const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int);
113126
# SQLITE_API int sqlite3_clear_bindings(sqlite3_stmt*);
114127

115128
function sqlite3_step(stmt::Ptr{Void})
@@ -238,7 +251,7 @@ function sqlite3_result_double(context::Ptr{Void},value::Float64)
238251
context,value)
239252
end
240253
# SQLITE_API void sqlite3_result_error(sqlite3_context*, const char*, int)
241-
function sqlite3_result_error(context::Ptr{Void},msg::String)
254+
function sqlite3_result_error(context::Ptr{Void},msg::AbstractString)
242255
return ccall( (:sqlite3_result_error, sqlite3_lib),
243256
Void, (Ptr{Void},Ptr{Uint8},Cint),
244257
context,value,sizeof(msg)+1)
@@ -268,7 +281,7 @@ function sqlite3_result_null(context::Ptr{Void})
268281
context)
269282
end
270283
# SQLITE_API void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*));
271-
function sqlite3_result_text(context::Ptr{Void},value::String)
284+
function sqlite3_result_text(context::Ptr{Void},value::AbstractString)
272285
return ccall( (:sqlite3_result_text, sqlite3_lib),
273286
Void, (Ptr{Void},Ptr{Uint8},Cint,Ptr{Void}),
274287
context,value,sizeof(value)+1,SQLITE_TRANSIENT)
@@ -292,7 +305,7 @@ end
292305
# SQLITE_API void sqlite3_result_error_code(sqlite3_context*, int)
293306

294307

295-
function sqlite3_create_function_v2(db::Ptr{Void},name::String,nargs::Integer,
308+
function sqlite3_create_function_v2(db::Ptr{Void},name::AbstractString,nargs::Integer,
296309
enc::Integer,data::Ptr{Void},func::Ptr{Void},
297310
step::Ptr{Void},final::Ptr{Void},
298311
destructor::Ptr{Void})
@@ -390,7 +403,7 @@ function sqlite3_os_end()
390403
Cint, (),
391404
)
392405
end
393-
function sqlite3_free_table(result::Array{String,1})
406+
function sqlite3_free_table(result::Array{AbstractString,1})
394407
return ccall( (:sqlite3_free_table, sqlite_lib),
395408
Void, (Ptr{Ptr{Void}},),
396409
result)
@@ -441,18 +454,18 @@ end
441454
# SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg);
442455

443456
# Not directly used
444-
function sqlite3_open_v2(file::String,handle::Array{Ptr{Void},1},flags::Cint,vfs::String)
457+
function sqlite3_open_v2(file::AbstractString,handle::Array{Ptr{Void},1},flags::Cint,vfs::AbstractString)
445458
return ccall( (:sqlite3_open_v2, sqlite3_lib),
446459
Cint, (Ptr{Uint8},Ptr{Void},Cint,Ptr{Uint8}),
447460
file,handle,flags,vfs)
448461
end
449-
function sqlite3_prepare(handle::Ptr{Void},query::String,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
462+
function sqlite3_prepare(handle::Ptr{Void},query::AbstractString,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
450463
@NULLCHECK handle
451464
return ccall( (:sqlite3_prepare, sqlite3_lib),
452465
Cint, (Ptr{Void},Ptr{Uint8},Cint,Ptr{Void},Ptr{Void}),
453466
handle,query,sizeof(query),stmt,unused)
454467
end
455-
function sqlite3_prepare16(handle::Ptr{Void},query::String,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
468+
function sqlite3_prepare16(handle::Ptr{Void},query::AbstractString,stmt::Array{Ptr{Void},1},unused::Array{Ptr{Void},1})
456469
@NULLCHECK handle
457470
return ccall( (:sqlite3_prepare16, sqlite3_lib),
458471
Cint, (Ptr{Void},Ptr{Uint8},Cint,Ptr{Void},Ptr{Void}),

src/show.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ begin
3838
ourshowcompact(io, x)
3939
return position(io)
4040
end
41-
ourstrwidth(x::String) = strwidth(x) + 2 # -> Int
41+
ourstrwidth(x::AbstractString) = strwidth(x) + 2 # -> Int
4242
ourstrwidth(s::Symbol) = int(ccall(:u8_strwidth,
4343
Csize_t,
4444
(Ptr{Uint8}, ),
@@ -61,7 +61,7 @@ end
6161
#' ourshowcompact(STDOUT, "abc")
6262
#' ourshowcompact(STDOUT, 10000)
6363
ourshowcompact(io::IO, x::Any) = showcompact(io, x) # -> Nothing
64-
ourshowcompact(io::IO, x::String) = showcompact(io, x) # -> Nothing
64+
ourshowcompact(io::IO, x::AbstractString) = showcompact(io, x) # -> Nothing
6565
ourshowcompact(io::IO, x::Symbol) = print(io, x) # -> Nothing
6666

6767
#' @description
@@ -83,7 +83,7 @@ ourshowcompact(io::IO, x::Symbol) = print(io, x) # -> Nothing
8383
#' chunk of the AbstractDataFrame that would be rendered to IO. Can
8484
#' be empty if the AbstractDataFrame would be printed without any
8585
#' ellipses.
86-
#' @param rowlabel::String The label that will be used when rendered the
86+
#' @param rowlabel::AbstractString The label that will be used when rendered the
8787
#' numeric ID's of each row. Typically, this will be set to "Row".
8888
#'
8989
#' @returns widths::Vector{Int} The maximum string widths required to render

0 commit comments

Comments
 (0)