Last active
August 29, 2015 14:16
-
-
Save threez/d5e0a53f331e88256b3f to your computer and use it in GitHub Desktop.
minimal sqlite3 driver
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usb/bin/env ruby | |
require 'fiddle' | |
require 'fiddle/import' | |
require 'pp' | |
module Sqlite3 | |
SQLITE_OK = 0 | |
module Driver | |
extend Fiddle::Importer | |
dlload 'libsqlite3.dylib' | |
extern 'char* sqlite3_errstr(int)' | |
extern 'int sqlite3_open(const char *, sqlite3**)' | |
extern 'int sqlite3_exec(sqlite3*, const char *, void *, void *, char **)' | |
extern 'int sqlite3_close(sqlite3*)' | |
end | |
class Error < StandardError; end | |
class Connection | |
include Fiddle | |
CALLBACK =[ TYPE_VOIDP, TYPE_INT, TYPE_VOIDP, TYPE_VOIDP ].freeze | |
def initialize(uri) | |
@db = Pointer.malloc(SIZEOF_VOIDP) | |
check Driver.sqlite3_open(uri.to_s, @db.ref) | |
end | |
def close | |
check Driver.sqlite3_close(@db) | |
end | |
def exec(stmt, &handler) | |
@errptr = Pointer.malloc(SIZEOF_VOIDP) | |
rownr = 0 | |
column_cache = {} | |
cb = Closure::BlockCaller.new(TYPE_INT, CALLBACK) do |_, argc, argv, columns| | |
row = {} | |
argc.times do |i| | |
column = column_cache[i] || begin | |
column_cache[i] = (columns + i * SIZEOF_VOIDP).ptr.to_s | |
.downcase.to_sym | |
end | |
value = (argv + i * SIZEOF_VOIDP).ptr.to_s | |
if value =~ /^\d+\.\d+$/ | |
value = value.to_f | |
elsif value =~ /^\d+$/ | |
value = value.to_i | |
end | |
row[column] = value | |
end | |
handler.call(row, rownr) | |
rownr += 1 | |
0 | |
end if block_given? | |
if Driver.sqlite3_exec(@db, stmt, cb, 0, @errptr.ref) != SQLITE_OK | |
fail Error, @errptr.to_s | |
end | |
ensure | |
@errptr.free | |
end | |
def check(error_code) | |
if error_code != SQLITE_OK | |
fail Error, Driver.sqlite3_errstr(error_code).to_s | |
end | |
end | |
end | |
end | |
connection = Sqlite3::Connection.new(":memory:") | |
connection.exec "CREATE TABLE COMPANY(" + | |
"ID INT PRIMARY KEY NOT NULL," + | |
"NAME TEXT NOT NULL," + | |
"AGE INT NOT NULL," + | |
"ADDRESS CHAR(50)," + | |
"SALARY REAL );" | |
connection.exec "INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " + | |
"VALUES (1, 'Paul', 32, 'California', 20000.00 ); " + | |
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY) " + | |
"VALUES (2, 'Allen', 25, 'Texas', 15000.00 ); " + | |
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" + | |
"VALUES (3, 'Teddy', 23, 'Norway', 20000.00 );" + | |
"INSERT INTO COMPANY (ID,NAME,AGE,ADDRESS,SALARY)" + | |
"VALUES (4, 'Mark', 25, 'Rich-Mond', 65000.00 );" | |
connection.exec "SELECT * from COMPANY" do |row, i| | |
p [i, row] | |
end | |
connection.close |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment