Skip to content

Commit 29de2b6

Browse files
committed
Merge pull request #93 from simonbyrne/sb/escape
escape identifiers in SQL statements
2 parents a227bc4 + b367878 commit 29de2b6

File tree

3 files changed

+33
-22
lines changed

3 files changed

+33
-22
lines changed

src/SQLite.jl

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ function execute!(db::DB,sql::AbstractString)
187187
return execute!(stmt)
188188
end
189189

190+
"Escape SQLite identifiers (e.g. column, table or index names). Can be either
191+
a string, or a vector of strings (note does not check for null characters).
192+
A vector of identifiers will be separated by commas."
193+
esc_id(x::AbstractString) = "\""*replace(x,"\"","\"\"")*"\""
194+
esc_id{S<:AbstractString}(X::AbstractVector{S}) = join(map(esc_id,X),',')
195+
196+
190197
# Transaction-based commands
191198
"""
192199
Begin a transaction in the spedified `mode`, default = "DEFERRED".
@@ -232,43 +239,46 @@ rollback(db) = execute!(db, "ROLLBACK TRANSACTION;")
232239
rollback(db, name) = execute!(db, "ROLLBACK TRANSACTION TO SAVEPOINT $(name);")
233240

234241
"drop the SQLite table `table` from the database `db`; `ifexists=true` will prevent an error being thrown if `table` doesn't exist"
235-
function drop!(db::DB,table::AbstractString;ifexists::Bool=false)
236-
exists = ifexists ? "if exists" : ""
242+
function drop!(db::DB, table::AbstractString; ifexists::Bool=false)
243+
exists = ifexists ? "IF EXISTS" : ""
237244
transaction(db) do
238-
execute!(db,"drop table $exists $table")
245+
execute!(db,"DROP TABLE $exists $(esc_id(table))")
239246
end
240-
execute!(db,"vacuum")
247+
execute!(db,"VACUUM")
241248
return
242249
end
250+
243251
"drop the SQLite index `index` from the database `db`; `ifexists=true` will not return an error if `index` doesn't exist"
244252
function dropindex!(db::DB,index::AbstractString;ifexists::Bool=false)
245-
exists = ifexists ? "if exists" : ""
253+
exists = ifexists ? "IF EXISTS" : ""
246254
transaction(db) do
247-
execute!(db,"drop index $exists $index")
255+
execute!(db,"DROP INDEX $exists $(esc_id(index))")
248256
end
249257
return
250258
end
259+
251260
"""
252-
create the SQLite index `index` on the table `table` using `cols`, which may be a single column or comma-delimited list of columns.
261+
create the SQLite index `index` on the table `table` using `cols`, which may be a single column or vector of columns.
253262
`unique` specifies whether the index will be unique or not.
254263
`ifnotexists=true` will not throw an error if the index already exists
255264
"""
256-
function createindex!(db::DB,table::AbstractString,index::AbstractString,cols
257-
;unique::Bool=true,ifnotexists::Bool=false)
258-
u = unique ? "unique" : ""
259-
exists = ifnotexists ? "if not exists" : ""
265+
function createindex!{S<:AbstractString}(db::DB,table::AbstractString,index::AbstractString,cols::Union{S,AbstractVector{S}}
266+
;unique::Bool=true,ifnotexists::Bool=false)
267+
u = unique ? "UNIQUE" : ""
268+
exists = ifnotexists ? "IF NOT EXISTS" : ""
260269
transaction(db) do
261-
execute!(db,"create $u index $exists $index on $table ($cols)")
270+
execute!(db,"CREATE $u INDEX $exists $(esc_id(index)) ON $(esc_id(table)) ($(esc_id(cols))")
262271
end
263-
execute!(db,"analyze $index")
272+
execute!(db,"ANALYZE $index")
264273
return
265274
end
275+
266276
"removes duplicate rows from `table` based on the values in `cols` which may be a single column or comma-delimited list of columns"
267277
function removeduplicates!(db,table::AbstractString,cols::AbstractString)
268278
transaction(db) do
269-
execute!(db,"delete from $table where rowid not in (select max(rowid) from $table group by $cols);")
279+
execute!(db,"DELETE FROM $(esc_id(table)) WHERE _ROWID_ NOT IN (SELECT max(_ROWID_) from $(esc_id(table)) GROUP BY $(esc_id(cols)));")
270280
end
271-
execute!(db,"analyze $table")
281+
execute!(db,"ANALYZE $table")
272282
return
273283
end
274284

src/Sink.jl

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ can optionally provide an existing SQLite table name or new name that a created
1414
function Sink(schema::Data.Schema,db::DB,tablename::AbstractString="julia_"*randstring();temp::Bool=false,ifnotexists::Bool=true)
1515
rows, cols = size(schema)
1616
temp = temp ? "TEMP" : ""
17-
ifnotexists = ifnotexists ? "if not exists" : ""
18-
columns = [string(schema.header[i],' ',sqlitetype(schema.types[i])) for i = 1:cols]
19-
SQLite.execute!(db,"CREATE $temp TABLE $ifnotexists $tablename ($(join(columns,',')))")
17+
ifnotexists = ifnotexists ? "IF NOT EXISTS" : ""
18+
columns = [string(esc_id(schema.header[i]),' ',sqlitetype(schema.types[i])) for i = 1:cols]
19+
SQLite.execute!(db,"CREATE $temp TABLE $ifnotexists $(esc_id(tablename)) ($(join(columns,',')))")
2020
params = chop(repeat("?,",cols))
21-
stmt = SQLite.Stmt(db,"insert into $tablename values ($params)")
21+
stmt = SQLite.Stmt(db,"INSERT INTO $(esc_id(tablename)) VALUES ($params)")
2222
return Sink(schema,db,utf8(tablename),stmt)
2323
end
2424

@@ -58,7 +58,7 @@ function Data.stream!(dt::Data.Table,sink::SQLite.Sink)
5858
end
5959
end
6060
end
61-
SQLite.execute!(sink.db,"analyze $(sink.tablename)")
61+
SQLite.execute!(sink.db,"ANALYZE $(esc_id(sink.tablename))")
6262
return sink
6363
end
6464
# CSV.Source
@@ -90,6 +90,6 @@ function Data.stream!(source::CSV.Source,sink::SQLite.Sink)
9090
end
9191
end
9292
end
93-
SQLite.execute!(sink.db,"analyze $(sink.tablename)")
93+
SQLite.execute!(sink.db,"ANALYZE $(esc_id(sink.tablename))")
9494
return sink
9595
end

src/Source.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,10 @@ function query(db::DB,sql::AbstractString, values=[];rows::Int=0,stricttypes::Bo
132132
so = Source(db,sql,values;rows=rows,stricttypes=stricttypes)
133133
return Data.stream!(so,Data.Table)
134134
end
135+
135136
"returns a list of tables in `db`"
136137
tables(db::DB) = query(db,"SELECT name FROM sqlite_master WHERE type='table';")
137138
"returns a list of indices in `db`"
138139
indices(db::DB) = query(db,"SELECT name FROM sqlite_master WHERE type='index';")
139140
"returns a list of columns in `table`"
140-
columns(db::DB,table::AbstractString) = query(db,"pragma table_info($table)")
141+
columns(db::DB,table::AbstractString) = query(db,"PRAGMA table_info($(esc_id(table)))")

0 commit comments

Comments
 (0)