[plt-scheme] Problems with ffi
Hi,
For the past days, I've been strugling with ffi, trying to map a
complex struct, and I was hoping for some help on this. My C is a bit
rusty, and I'm fairly new to Scheme as well, so you might say I'm a
bit out of my league, but I'm not going to back down now.
I'm working on creating bindings for libmysqlclient (There's a
git-repo at https://github.com/troelskn/mr-mysql/tree). I didn't write
all the code myself, but I have worked through it and understand it
quite well thus far. My problem now, is how to map a rather
complicated struct (MYSQL_BIND). This struct contains a number of
pointers to places where the C-code will write data back to, and I'm
lost in the various mechanisms for pointer-handling in ffi.
http://dev.mysql.com/doc/refman/5.1/en/mysql-stmt-execute.html shows
how to use the api in C. I'm basically trying to accomplish this part
(slightly simplified):
#define MYSQL_TYPE_STRING 254
#define STRING_SIZE 50
MYSQL_BIND bind;
char str_data[STRING_SIZE];
unsigned long str_length;
my_bool is_null;
/* STRING PARAM */
bind.buffer_type= MYSQL_TYPE_STRING;
bind.buffer= (char *)str_data;
bind.buffer_length= STRING_SIZE;
bind.is_null= 0;
bind.length= &str_length;
The definition of MYSQL_BIND looks like this (from mysql.h):
typedef struct st_mysql_bind
{
unsigned long *length; /* output length pointer */
my_bool *is_null; /* Pointer to null indicator */
void *buffer; /* buffer to get/put data */
/* set this if you want to track data truncations happened during fetch */
my_bool *error;
enum enum_field_types buffer_type; /* buffer type */
/* output buffer length, must be set when fetching str/binary */
unsigned long buffer_length;
unsigned char *row_ptr; /* for the current data position */
unsigned long offset; /* offset position for char/binary fetch */
unsigned long length_value; /* Used if length is 0 */
unsigned int param_number; /* For null count and error messages */
unsigned int pack_length; /* Internal length for packed data */
my_bool error_value; /* used if error is 0 */
my_bool is_unsigned; /* set if integer type is unsigned */
my_bool long_data_used; /* If used with mysql_send_long_data */
my_bool is_null_value; /* Used if is_null is 0 */
void (*store_param_func)(NET *net, struct st_mysql_bind *param);
void (*fetch_result)(struct st_mysql_bind *, MYSQL_FIELD *,
unsigned char **row);
void (*skip_result)(struct st_mysql_bind *, MYSQL_FIELD *,
unsigned char **row);
} MYSQL_BIND;
What I have tried in scheme, is this:
#lang scheme/base
(require (lib "foreign.ss"))
(unsafe!)
(define libmysqlclient (ffi-lib "libmysqlclient"))
(define _my-bool
(make-ctype _byte
(lambda (x) (if x 1 0))
(lambda (x) (not (eq? 0 x)))))
(define-cstruct _mysql-bind
((length _pointer)
(is-null (_ptr io _my-bool))
(buffer _pointer)
(error _pointer)
(buffer-type _uint)
(buffer-length _ulong)
(row-ptr _string)
(offset _ulong)
(length-value _ulong)
(param-number _uint)
(pack-length _uint)
(error-value _my-bool)
(is-unsigned _my-bool)
(long-data-used _my-bool)
(is-null-value _my-bool)
(store-param-func _pointer)
(fetch-result _pointer)
(skip-result _pointer)))
(printf "testing~%")
(define buffer (malloc 50))
(define str-length (malloc _ulong))
(define is-error (malloc _my-bool))
(define binding (make-mysql-bind
str-length ; length = &str_length;
#f ; is_null = 0;
buffer ; buffer = (char *)str_data;
is-error
254 ; buffer_type = MYSQL_TYPE_STRING;
50 ; buffer_length = STRING_SIZE;
0
0
0
0
0
0
0
0
0
0
0
0))
(print binding)
When I run the above script, I get the following error:
testing
ptr-set!: expects type <C-type> as 2nd argument, given:
#<procedure:mysql-bind-buffer-type>; other arguments were:
#<cpointer:mysql-bind> abs 8 #<cpointer>
=== context ===
make-mysql-bind
What does that mean, and what am I doing wrong?
If it matters, I'm using MzScheme v4.1.4.3 (compiled from trunk)
--
troels