lib/motion-sqlite3/statement.rb
module SQLite3
class Statement
def initialize(db, sql, params)
@db = db
@handle = Pointer.new(::Sqlite3_stmt.type)
@result = nil
prepare(sql)
bind(params)
end
def done?
@result == SQLITE_DONE
end
def execute
step
ResultSet.new(self, @handle)
end
def finalize
sqlite3_finalize(@handle.value_with_autorelease)
end
def step
@result = sqlite3_step(@handle.value_with_autorelease)
unless @result == SQLITE_DONE || @result == SQLITE_ROW
raise SQLite3Error, sqlite3_errmsg(@db.value_with_autorelease)
end
end
private
def bind(params)
case params
when Hash
params.each { |name, value| bind_parameter(name, value) }
when Array
params.each_with_index { |value, i| bind_parameter(i+1, value) }
when NilClass
else
raise ArgumentError, "params must be either a Hash or an Array"
end
end
def bind_parameter(name, value)
index = column_index(name)
case value
when NilClass
result = sqlite3_bind_null(@handle.value_with_autorelease, index)
when String, Symbol
result = sqlite3_bind_text(@handle.value_with_autorelease, index, value, -1, lambda { |arg| })
when Integer
result = sqlite3_bind_int64(@handle.value_with_autorelease, index, value)
when Float
result = sqlite3_bind_double(@handle.value_with_autorelease, index, value)
when NSDatavalue
result = sqlite3_bind_blob(@handle.value_with_autorelease, index, value.bytes, value.length, lambda { |arg| })
else
raise SQLite3Error, "unable to bind #{value} to #{name}: unexpected type #{value.class}"
end
raise SQLite3Error, sqlite3_errmsg(@db.value_with_autorelease) if result != SQLITE_OK
end
def column_index(name)
index = 0
case name
when String, Symbol
index = sqlite3_bind_parameter_index(@handle.value_with_autorelease, ":#{name}")
raise SQLite3Error, "couldn't find index for #{name}!" if index == 0
when Integer
index = name
end
index
end
def prepare(sql)
remainder = Pointer.new(:string)
result = sqlite3_prepare_v2(@db.value_with_autorelease, sql, -1, @handle, remainder)
raise SQLite3Error, sqlite3_errmsg(@db.value_with_autorelease) if result != SQLITE_OK
end
end
end