/********************************************************************************* * Package : c-sqld-mysql.c * Author : Hans Oesterholt-Dijkema. * Copyright : HOD 2004/2005. * License : The Elemental Programming Artistic License. * CVS : $Id: c-sqld-mysql.c,v 1.4 2006/01/04 20:15:18 HansOesterholt Exp $ *********************************************************************************/ #include "sqlid.h" #include #include #include #ifdef MZSCHEME # include # include "c-threads.c" #endif #include /*#define DBG(a) a*/ #define DBG(a) /* =head1 Name SQLD-MYSQL - C Part =head1 Author Hans Oesterholt-Dijkema =head1 Copyright/License (c) 2004 Hans Oesterholt-Dijkema, LGPL. =head1 Version $Id: c-sqld-mysql.c,v 1.4 2006/01/04 20:15:18 HansOesterholt Exp $ */ typedef struct { MYSQL *myData; } mysql_t; typedef struct { mysql_t *handle; int nrows; int nfields; Scheme_Object **fields; } mysql_query_t; #ifdef WIN32 #define ALLOCA(a) _alloca(a) #define FREE_ALLOCA(p) #else #define ALLOCA(a) _alloca(a) #define FREE_ALLOCA(p) #endif static int c_mysql_client_version(void) { return mysql_get_client_version(); } static int c_mysql_server_version(MYSQL *myData) { return mysql_get_server_version(myData); } static Scheme_Object *gc_strdup(char *s) /* utf8 s */ { if (s==NULL) { s=""; } return scheme_make_utf8_string(s); } static Scheme_Object *MYSQL_Type=NULL; static Scheme_Object *Query_Type=NULL; #define init_types() \ if (MYSQL_Type==NULL) { \ MYSQL_Type=scheme_make_byte_string("MySQL"); \ Query_Type=scheme_make_byte_string("MySQL_Query"); \ } #define SCHEME_STR_VAL(a) SCHEME_BYTE_STR_VAL(scheme_char_string_to_byte_string(a)) #define STRVAL(a) SCHEME_STR_VAL(a) #define EQ_CTYPE(cobj,type) (SCHEME_CPTR_TYPE(cobj)==type) #define IS_STRINGP(obj) SCHEME_CHAR_STRINGP(obj) char *get_dsn_part(char *part,char *dsn) { char *p=strstr(dsn,part); char *val=NULL; if (p!=NULL) { p+=strlen(part); if (p[0]=='\0' || isspace(p[0])) { } else { char *b=p; val=p; for(;p[0]!='\0' && !isspace(p[0]);p++); { char c=p[0]; p[0]='\0'; val=(char *) scheme_malloc(strlen(b)+1); strcpy(val,b); p[0]=c; } } } return val; } #define FUNC "c_mysql_open" static Scheme_Object *c_mysql_open(int argc, Scheme_Object **argv) { mysql_t *handle=(mysql_t *) scheme_malloc(sizeof(mysql_t)); init_types(); if (!IS_STRINGP(argv[0])) { scheme_wrong_type(FUNC,"string",0,argc,argv); } { char *host=NULL; char *user=NULL; char *passwd=NULL; char *db=NULL; unsigned int port=0; char *dsn=STRVAL(argv[0]); host=get_dsn_part("host=",dsn); user=get_dsn_part("user=",dsn); passwd=get_dsn_part("passwd=",dsn); db=get_dsn_part("db=",dsn); if (db==NULL) { db=get_dsn_part("dbname=",dsn); } { char *p=get_dsn_part("port=",dsn); if (p!=NULL) { port=atoi(p); } } DBG(printf("dsn=%s\n",dsn)); DBG(printf("host=%s, user=%s, passwd=%s, db=%s, port=%d\n",host,user,passwd,db,port)); handle->myData=mysql_init(NULL); { MYSQL *conn=mysql_real_connect(handle->myData, host, user, passwd, db, port, NULL, 0 ); return scheme_make_cptr(handle,MYSQL_Type); } } } #undef FUNC #define FUNC "c_mysql_close" static Scheme_Object *c_mysql_close(int argc, Scheme_Object **argv) { init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } else if (!EQ_CTYPE(argv[0],MYSQL_Type)) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } { mysql_t *handle=(mysql_t *) SCHEME_CPTR_VAL(argv[0]); if (handle->myData==NULL) { scheme_signal_error(FUNC ": Invalid mysql handle (MYSQL: NULL pointer)"); } mysql_close(handle->myData); handle->myData=NULL; } return scheme_void; } #undef FUNC #define FUNC "c_mysql_escape" static Scheme_Object *c_mysql_escape(int argc, Scheme_Object **argv) { Scheme_Object *obj; init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } else if (!EQ_CTYPE(argv[0],MYSQL_Type)) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } if (!IS_STRINGP(argv[1])) { scheme_wrong_type(FUNC,"string",1,argc,argv); } { mysql_t *handle=(mysql_t *) SCHEME_CPTR_VAL(argv[0]); char *string=STRVAL(argv[1]); int len=strlen(string); char *to=(char *) malloc((len+1)*2); if (handle->myData==NULL) { scheme_signal_error(FUNC ": Invalid mysql handle (MYSQL: NULL pointer)"); } mysql_real_escape_string(handle->myData,to,string,len); obj=gc_strdup(to); free(to); } return obj; } #undef FUNC static char *trim(char *s) { int N=strlen(s)-1; for(;N>=0 && isspace(s[N]);N--); s[N+1]='\0'; { char *p=s; for(;p[0]!='\0' && isspace(p[0]);p++); return p; } } typedef struct { mysql_t *handle; char *query; int result; int ready; } mysql_exec_t; static int query(void *data) { mysql_exec_t *H=(mysql_exec_t *) data; { mysql_t *handle=H->handle; char *query=H->query; int i; int N=strlen(query); char *q; char *b; int in_string=0; int R; b=q=trim(query); R=0; for(i=0;R==0 && imyData,b,strlen(b)); q[i]=c; b=&q[i+1]; } } if (R==0 && b!=&q[i]) { R=mysql_real_query(handle->myData,b,strlen(b)); } H->result=R; } H->ready=(1==1); return 0; } static int query_ready(Scheme_Object *data) { mysql_exec_t *H=(mysql_exec_t *) data; return H->ready; } #define FUNC "c_mysql_query" static Scheme_Object *c_mysql_query(int argc, Scheme_Object **argv) //void *db,char *query) { Scheme_Object *obj; init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } else if (!EQ_CTYPE(argv[0],MYSQL_Type)) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } if (!IS_STRINGP(argv[1])) { scheme_wrong_type(FUNC,"string",1,argc,argv); } { mysql_t *handle=(mysql_t *) SCHEME_CPTR_VAL(argv[0]); int R=0; if (handle->myData==NULL) { scheme_signal_error(FUNC ": Invalid mysql handle (MYSQL: NULL pointer)"); } { mysql_exec_t *H=(mysql_exec_t *) malloc(sizeof(mysql_exec_t)); H->handle=handle; H->query=SCHEME_STR_VAL(argv[1]); H->result=0; H->ready=0; { t_c_thread_id id; id=c_thread_create(query,(void *) H); scheme_block_until(query_ready,NULL,(Scheme_Object *) H,-1); c_thread_join(id); } R=H->result; free(H); } /* Query has been done, fetch results */ { mysql_query_t *q=(mysql_query_t *) scheme_malloc(sizeof(mysql_query_t)); MYSQL_RES *res=mysql_store_result(handle->myData); q->handle=handle; if (res==NULL) { q->nrows=0; q->nfields=0; q->fields=NULL; } else { q->nrows=mysql_num_rows(res); q->nfields=mysql_num_fields(res); DBG(printf("Query result: %d, %d\n",q->nrows,q->nfields)); q->fields=(Scheme_Object **) scheme_malloc(sizeof(Scheme_Object *)*q->nfields*q->nrows); { MYSQL_ROW row; unsigned long *lengths; int i,k,M=q->nfields,N=q->nrows; Scheme_Object **fields=q->fields; for(i=0;inrows); } return obj; } #undef FUNC #define FUNC "c_mysql_nfields" static Scheme_Object *c_mysql_nfields(int argc, Scheme_Object **argv) { Scheme_Object *obj; init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL_Query",0,argc,argv); } else if (!EQ_CTYPE(argv[0],Query_Type)) { scheme_wrong_type(FUNC,"MySQL_Query",0,argc,argv); } { mysql_query_t *q=SCHEME_CPTR_VAL(argv[0]); obj=scheme_make_integer(q->nfields); } return obj; } #undef FUNC #define FUNC "c_mysql_field" static Scheme_Object *c_mysql_field(int argc, Scheme_Object **argv) { Scheme_Object *obj; init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL_Query",0,argc,argv); } else if (!EQ_CTYPE(argv[0],Query_Type)) { scheme_wrong_type(FUNC,"MySQL_Query",0,argc,argv); } if (!SCHEME_INTP(argv[1])) { scheme_wrong_type("c-mysql-field","integer",1,argc,argv); } if (!SCHEME_INTP(argv[2])) { scheme_wrong_type("c-mysql-field","integer",2,argc,argv); } { mysql_query_t *q=SCHEME_CPTR_VAL(argv[0]); int row=SCHEME_INT_VAL(argv[1]); int field=SCHEME_INT_VAL(argv[2]); if (row>=q->nrows) { scheme_signal_error(FUNC ": row out of bound"); } { int N=q->nfields; if (field>=N) { scheme_signal_error(FUNC ": field out of bound"); } DBG(printf("q->nrows=%d, q->nfields=%d, q->fields=%p (%d,%d)\n", q->nrows,q->nfields,q->fields, row, field)); obj=q->fields[row*N+field]; } } return obj; } #undef FUNC #define FUNC "c_mysql_lasterr" static Scheme_Object *c_mysql_lasterr(int argc, Scheme_Object **argv) { Scheme_Object *obj; init_types(); if (!SCHEME_CPTRP(argv[0])) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } else if (!EQ_CTYPE(argv[0],MYSQL_Type) && !EQ_CTYPE(argv[0],Query_Type)) { scheme_wrong_type(FUNC,"MySQL",0,argc,argv); } if (EQ_CTYPE(argv[0],MYSQL_Type)) { mysql_t *handle=(mysql_t *) SCHEME_CPTR_VAL(argv[0]); if (handle->myData==NULL) { scheme_signal_error(FUNC ": Invalid mysql handle (MYSQL: NULL pointer)"); } obj=gc_strdup((char *) mysql_error(handle->myData)); } else { mysql_query_t *q=SCHEME_CPTR_VAL(argv[0]); mysql_t *handle=q->handle; if (handle->myData==NULL) { scheme_signal_error(FUNC ": Invalid mysql handle (MYSQL: NULL pointer)"); } obj=gc_strdup((char *) mysql_error(q->handle->myData)); } return obj; } #undef FUNC static Scheme_Object *c_mysql_version(int argc, Scheme_Object **argv) { return scheme_make_integer(c_mysql_client_version()); } Scheme_Object *scheme_reload(Scheme_Env *env) { Scheme_Env *menv; Scheme_Object *proc; menv = scheme_primitive_module(scheme_intern_symbol("c-sqld-mysql"),env); proc = scheme_make_prim_w_arity(c_mysql_version, "c-mysql-version", 0, 0); scheme_add_global("c-mysql-version", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_open, "c-mysql-open", 1, 1); scheme_add_global("c-mysql-open", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_close, "c-mysql-close", 1, 1); scheme_add_global("c-mysql-close", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_query, "c-mysql-query", 2, 2); scheme_add_global("c-mysql-query", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_nrows, "c-mysql-nrows", 1, 1); scheme_add_global("c-mysql-nrows", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_nfields, "c-mysql-nfields", 1, 1); scheme_add_global("c-mysql-nfields", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_field, "c-mysql-field", 3, 3); scheme_add_global("c-mysql-field", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_lasterr, "c-mysql-lasterr", 1, 1); scheme_add_global("c-mysql-lasterr", proc, menv); proc = scheme_make_prim_w_arity(c_mysql_escape, "c-mysql-escape", 2, 2); scheme_add_global("c-mysql-escape", proc, menv); scheme_finish_primitive_module(menv); return scheme_void; } Scheme_Object *scheme_initialize(Scheme_Env *env) { return scheme_reload(env); } Scheme_Object *scheme_module_name(void) { return scheme_intern_symbol("c-sqld-mysql"); } /*=verbatim =cut */