Arc Forumnew | comments | leaders | submitlogin
ffi sqlite3 - help
5 points by jmatt 6040 days ago | 7 comments
I'm working on writing a ffi for SQLite3. The goal is to replace John Graham-Cumming's sqlite network wrapper. The first step will be to implement open exec and close. That will be enough to get a functional SQLite3 database. This is my first time implementing any ffi. Also I haven't had a chance to clean up or refactor the code. So I'll apologize for that now.

As of right now sqlite3-open works. sqlite3-exec seg faults with 0x3c. I'm currently deving on mac os x. But I could jump over to my linux box if needed. In the end I'm hoping to get the code to work on linux, mac os x and windows. I'm looking for some help to get it functional. If anyone can help it is much appreciated!

The Code:

  (require "ffi.arc")

  ;; begin callback

  ;; this list will hold all defined callbacks
  ;; without this, they would be garbage collected, because Scheme's runtime
  ;; doesn't know if the foreign runtime references or not the callbacks
  ;; this way, I'm sure that they'll never be garbage collected
  (= callbacks* nil)

  (def sqlite3-callback args ;(db3 int3 argin3 errormessage3)
  t);(prn db3 int3 argin3 errormessage3)

  ;; load the callback function into callbacks*
  (let cb (ffi-callback sqlite3-callback (list
					 cptr 
					 cint 
					 cstring 
					 cstring) 
		      cint)
  (push cb callbacks*) cb) ;Callback function

  (def topcb () (let cb (pop callbacks*) (push cb callbacks*) cb))

  ;dependency - mac os x dylib / linux .so / windows .dll
  (w/ffi "/opt/local/lib/libsqlite3" ;in mac os x "sudo port install sqlite3"
       ;int sqlite3_open(
       ;  const char *filename,   /* Database filename (UTF-8) */
       ;  sqlite3 **ppDb          /* OUT: SQLite db handle */
       ;);
       ;sqlite3_open
      (cdef sqlite3-open "sqlite3_open" cint (cstring cptr))
      ;int sqlite3_exec(
      ;  sqlite3*,                                  /* An open database */
      ;  const char *sql,                           /* SQL to be evaluted */
      ;  int (*callback)(void*,int,char**,char**),  /* Callback function */
      ;  void *,                                    /* 1st argument to callback */
      ;  char **errmsg                              /* Error msg written here */
      ;);
      ;sqlite3_exec
      (cdef sqlite3-exec "sqlite3_exec" cint (cptr ;sqlite3* - An open database
					       cstring ;SQL to be evaluated
					       cfptr;function pointer
					       cptr ;1st argument to callback
					       cstring)) ;Error msg - need to GC this.
      ;int sqlite3_close(sqlite3 *);
      ;sqlite3_close
      (cdef sqlite3-close "sqlite3_close" cint (cptr)))
Load code:

  (= sqlite3 (cmalloc 4))
  (= sqltxt "create table bar (id integer primary key, text varchar(255));")
  (= sqlerrormsg "")
  (= sqltxtptr (cmalloc 4))
  (cpset sqltxtptr cstring sqltxt)
  (sqlite3-open "test" sqlite3)
  (sqlite3-exec sqlite3 sqltxt (topcb) sqltxtptr sqlerrormsg)
Don't forget to change w/ffi if you are going to try to run the code.

links ffi:

http://arclanguage.org/item?id=6053

http://arclanguage.org/item?id=5193

http://arclanguage.org/item?id=4706

links sqlite:

http://www.sqlite.org/c3ref/intro.html

http://www.jgc.org/blog/labels/arc.html



3 points by sacado 6036 days ago | link

OK, here we go :

  ; Implementation note : mzscheme's #f can be used as the C NULL pointer
  (= NULL* #f)

  (= callbacks* nil)
  (def sqlite3-callback args t)
  (let cb (ffi-callback sqlite3-callback (list cptr cint cptr cptr) cint)
    (push cb callbacks*) cb)

  ; Here, we defined cb as a callback of type cptr cint cptr cptr :
  ; no cstring here, as we have char** and not char *

  (def topcb () (let cb (pop callbacks*) (push cb callbacks*) cb))

  (w/ffi "libsqlite3" ;in mac os x "sudo port install sqlite3"
    (cdef sqlite3-open "sqlite3_open" cint (cstring cptr))
    (cdef sqlite3-exec "sqlite3_exec" cint (cptr cstring cfptr cptr cptr))
    ; Here again, cptr instead of cstring for error : we need a ptr to string
  (cdef sqlite3-close "sqlite3_close" cint (cptr)))

  ; Last warning : 2nd arg to sqlite3-open is a sqlite3**, i.e.
  ;  it returns the address of the actual sqlite3* used by sqlite3-exex & sqlite3-close

  (= &sqlite3 (cmalloc 4)) ; address of the actual sqlite3*
  (= sqltxt "create table bar (id integer primary key, text varchar(255));")
  (= sqlerrormsg (cmalloc 4))
  (= sqltxtptr NULL*)

  (sqlite3-open "test" &sqlite3)
  (= sqlite3 (cpref &sqlite3 cptr)) ; dereference to have an sqlite3*
  (sqlite3-exec sqlite3 sqltxt (topcb) sqltxtptr sqlerrormsg)
  (sqlite3-close sqlite3)
Not tried with an actual callback function, though, but on my machine it works perfectly...

-----

2 points by jmatt 6036 days ago | link

Thanks for the help. I'll test this out tonight.

Good to know that C NULL == mzscheme's #f.

-----

2 points by jmatt 6040 days ago | link

Ok here is a more specific question.

Given this C and ffi declaration:

  ;int sqlite3_exec(
  ;  sqlite3*,                                  /* An open database */
  ;  const char *sql,                           /* SQL to be evaluted */
  ;  int (*callback)(void*,int,char**,char**),  /* Callback function */
  ;  void *,                                    /* 1st argument to callback */
  ;  char **errmsg                              /* Error msg written here */
  ;);

  ;sqlite3_exec
  (cdef sqlite3-exec "sqlite3_exec" cint (cptr cstring cfptr cptr cstring))
Why is this call to it seg faulting (for details on parameters see load code above):

  (sqlite3-exec sqlite3 sqltxt (topcb) sqltxtptr sqlerrormsg)
Does this work for anyone else? Is there a problem with my parameter delcaration / setup?

Thanks ~

-----

1 point by sacado 6038 days ago | link

On the Arc level, it works perfectly well for me (no error, no segfault). But, when I try to (manually, with vi) open the db file (the "test" file), it's empty. Existing, but empty. I don't know why yet.

There's one thing that seems strange to me in the above declaration : char errmsg should not be declared as a cstring : it is a pointer to a string. I guess it should be declared as a cptr. I'll investigate more deeply later, when I'll find enough time...

-----

2 points by jmatt 6037 days ago | link

Yeah that is definitely a problem. I will work on this again tonight and see if I can get somewhere.

-----

2 points by sacado 6040 days ago | link

I'll try that & see if I can help you...

-----

1 point by jmatt 6040 days ago | link

Awesome, much appreciated.

-----