|
|
1.1 parser 1: /** @file
2: Parser MySQL driver.
3:
1.40 moko 4: Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com)
1.1 parser 5:
1.7 paf 6: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.1 parser 7:
1.36 misha 8: 2001-07-30 using MySQL 3.23.22b
1.3 paf 9:
1.36 misha 10: 2001-11-06 numrows on "HP-UX istok1 B.11.00 A 9000/869 448594332 two-user license"
1.3 paf 11: 3.23.42 & 4.0.0.alfa never worked, both subst & .sl version returned 0
1.1 parser 12: */
13:
14: #include "config_includes.h"
15:
16: #include "pa_sql_driver.h"
17:
1.45 ! moko 18: volatile const char * IDENT_PARSER3MYSQL_C="$Id: parser3mysql.C,v 1.44 2012-08-31 08:33:29 moko Exp $" IDENT_PA_SQL_DRIVER_H;
1.40 moko 19:
1.1 parser 20: #define NO_CLIENT_LONG_LONG
21: #include "mysql.h"
22: #include "ltdl.h"
23:
24: #define MAX_STRING 0x400
25: #define MAX_NUMBER 20
26:
27: #if _MSC_VER
28: # define snprintf _snprintf
1.2 parser 29: # define strcasecmp _stricmp
1.1 parser 30: #endif
31:
1.35 misha 32: // for mysql < 4.1
1.36 misha 33: #if !defined(CLIENT_MULTI_RESULTS) || !defined(CLIENT_MULTI_STATEMENTS)
34: # define OLD_MYSQL_CLIENT 1
35: #endif
36:
1.35 misha 37: #ifndef CLIENT_MULTI_RESULTS
1.36 misha 38: # define CLIENT_MULTI_RESULTS (1UL << 17)
1.35 misha 39: #endif
1.36 misha 40:
1.35 misha 41: #ifndef CLIENT_MULTI_STATEMENTS
1.36 misha 42: # define CLIENT_MULTI_STATEMENTS (1UL << 16)
1.35 misha 43: #endif
44:
1.34 misha 45: static char *lsplit(char *string, char delim){
1.32 misha 46: if(string) {
1.34 misha 47: if(char *v=strchr(string, delim)){
1.1 parser 48: *v=0;
49: return v+1;
50: }
1.32 misha 51: }
52: return 0;
1.1 parser 53: }
54:
1.34 misha 55: static char *lsplit(char **string_ref, char delim){
1.32 misha 56: char *result=*string_ref;
1.2 parser 57: char *next=lsplit(*string_ref, delim);
1.32 misha 58: *string_ref=next;
59: return result;
1.2 parser 60: }
61:
1.34 misha 62: static char* rsplit(char* string, char delim){
63: if(string){
64: if(char* v=strrchr(string, delim)){
1.26 paf 65: *v=0;
66: return v+1;
67: }
1.32 misha 68: }
69: return NULL;
1.26 paf 70: }
71:
1.34 misha 72: static void toupper_str(char *out, const char *in, size_t size){
1.19 paf 73: while(size--)
74: *out++=(char)toupper(*in++);
75: }
76:
1.38 misha 77: inline static bool is_column_transcode_required(enum_field_types type) {
78: switch(type) {
79: case MYSQL_TYPE_NULL:
80:
1.45 ! moko 81: #ifdef FIELD_TYPE_NEWDECIMAL
! 82: case MYSQL_TYPE_NEWDECIMAL:
! 83: #endif
1.38 misha 84: case MYSQL_TYPE_DECIMAL:
85: case MYSQL_TYPE_FLOAT:
86: case MYSQL_TYPE_DOUBLE:
87:
88: case MYSQL_TYPE_TINY:
89: case MYSQL_TYPE_SHORT:
90: case MYSQL_TYPE_LONG:
91: case MYSQL_TYPE_LONGLONG:
92: case MYSQL_TYPE_INT24:
1.45 ! moko 93: #ifdef FIELD_TYPE_BIT
1.38 misha 94: case MYSQL_TYPE_BIT:
1.45 ! moko 95: #endif
1.38 misha 96:
97: case MYSQL_TYPE_DATE:
98: case MYSQL_TYPE_NEWDATE:
99: case MYSQL_TYPE_TIME:
100: case MYSQL_TYPE_DATETIME:
101: case MYSQL_TYPE_YEAR:
102: case MYSQL_TYPE_TIMESTAMP:
103:
104: case MYSQL_TYPE_BLOB:
105: case MYSQL_TYPE_TINY_BLOB:
106: case MYSQL_TYPE_MEDIUM_BLOB:
107: case MYSQL_TYPE_LONG_BLOB:
108: return false;
109: break;
110: }
111: return true;
112: }
113:
114: inline static const char* strdup(SQL_Driver_services& services, char* str, size_t length) {
115: char *strm=(char*)services.malloc_atomic(length+1);
116: memcpy(strm, str, length);
117: strm[length]=0;
118: return (const char*)strm;
119: }
120:
1.14 paf 121: struct Connection {
1.16 paf 122: SQL_Driver_services* services;
1.15 paf 123:
1.14 paf 124: MYSQL* handle;
1.33 misha 125: const char* client_charset;
1.14 paf 126: bool autocommit;
127: };
128:
1.29 misha 129:
1.1 parser 130: /**
131: MySQL server driver
132: */
133: class MySQL_Driver : public SQL_Driver {
134: public:
135:
1.29 misha 136: MySQL_Driver() : SQL_Driver() {}
137:
1.35 misha 138: #ifndef FREEBSD4
1.29 misha 139: ~MySQL_Driver() {
140: if(mysql_server_end)
141: mysql_server_end();
1.1 parser 142: }
1.35 misha 143: #endif
1.1 parser 144:
145: /// get api version
146: int api_version() { return SQL_DRIVER_API_VERSION; }
1.33 misha 147:
1.1 parser 148: /// initialize driver by loading sql dynamic link library
1.4 paf 149: const char *initialize(char *dlopen_file_spec) {
1.1 parser 150: return dlopen_file_spec?
151: dlink(dlopen_file_spec):"client library column is empty";
152: }
1.33 misha 153:
1.1 parser 154: /** connect
1.23 paf 155: @param url
1.2 parser 156: format: @b user:pass@host[:port]|[/unix/socket]/database?
1.33 misha 157: charset=value& // transcode by server with command 'SET CHARACTER SET value'
1.32 misha 158: ClientCharset=charset& // transcode by parser
1.2 parser 159: timeout=3&
1.32 misha 160: compress=0&
161: named_pipe=1&
1.33 misha 162: autocommit=1&
1.35 misha 163: multi_statements=0 // allows more then one statement in one query
164: old_client=1 // simulates 3.xx client. not compatible with multi_statements option
1.33 misha 165: 3.x, 4.0
166: only option for charset is cp1251_koi8.
167: 4.1+ accept not 'cp1251_koi8' but 'cp1251', 'utf8' and much more
168: it is usable for transcoding using sql server
1.1 parser 169: */
170: void connect(
1.33 misha 171: char *url,
172: SQL_Driver_services& services,
173: void **connection_ref ///< output: Connection*
174: ){
1.23 paf 175: char *user=url;
1.26 paf 176: char *s=rsplit(user, '@');
1.1 parser 177: char *host=0;
178: char *unix_socket=0;
179: if(s && s[0]=='[') { // unix socket
180: unix_socket=1+s;
181: s=lsplit(unix_socket, ']');
182: } else { // IP
183: host=s;
184: }
185: char *db=lsplit(s, '/');
186: char *pwd=lsplit(user, ':');
187: char *error_pos=0;
188: char *port_cstr=lsplit(host, ':');
189: int port=port_cstr?strtol(port_cstr, &error_pos, 0):0;
1.2 parser 190: char *options=lsplit(db, '?');
191:
1.33 misha 192: char *charset=0;
1.35 misha 193:
194: #ifdef OLD_MYSQL_CLIENT
195: int client_flag=0;
196: #else
1.34 misha 197: int client_flag=CLIENT_MULTI_RESULTS;
1.35 misha 198: #endif
1.1 parser 199:
1.33 misha 200: Connection& connection=*(Connection *)services.malloc(sizeof(Connection));
201: *connection_ref=&connection;
1.15 paf 202: connection.services=&services;
1.32 misha 203: connection.handle=mysql_init(NULL);
1.33 misha 204: connection.client_charset=0;
1.14 paf 205: connection.autocommit=true;
1.2 parser 206:
1.32 misha 207: while(options){
208: if(char *key=lsplit(&options, '&')){
209: if(*key){
210: if(char *value=lsplit(key, '=')){
1.33 misha 211: if(strcmp(key, "ClientCharset")==0){ // transcoding with parser
1.21 paf 212: toupper_str(value, value, strlen(value));
1.33 misha 213: connection.client_charset=value;
1.32 misha 214: } else if(strcasecmp(key, "charset")==0){ // transcoding with server
1.33 misha 215: charset=value;
1.32 misha 216: } else if(strcasecmp(key, "timeout")==0){
1.2 parser 217: unsigned int timeout=(unsigned int)atoi(value);
1.14 paf 218: if(mysql_options(connection.handle, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout)!=0)
219: services._throw(mysql_error(connection.handle));
1.32 misha 220: } else if(strcasecmp(key, "compress")==0){
1.2 parser 221: if(atoi(value))
1.14 paf 222: if(mysql_options(connection.handle, MYSQL_OPT_COMPRESS, 0)!=0)
223: services._throw(mysql_error(connection.handle));
1.32 misha 224: } else if(strcasecmp(key, "named_pipe")==0){
1.2 parser 225: if(atoi(value))
1.33 misha 226: if(mysql_options(connection.handle, MYSQL_OPT_NAMED_PIPE, 0)!=0)
1.14 paf 227: services._throw(mysql_error(connection.handle));
1.39 misha 228: } else if(strcasecmp(key, "local_infile")==0){
229: if(atoi(value))
230: if(mysql_options(connection.handle, MYSQL_OPT_LOCAL_INFILE, 0)!=0)
231: services._throw(mysql_error(connection.handle));
1.32 misha 232: } else if(strcasecmp(key, "autocommit")==0){
1.31 misha 233: if(atoi(value)==0)
1.14 paf 234: connection.autocommit=false;
1.34 misha 235: } else if(strcasecmp(key, "multi_statements")==0){
1.35 misha 236: #ifdef OLD_MYSQL_CLIENT
237: services._throw("driver was built with old mysql includes so multi_statements option can't be used");
238: #else
1.34 misha 239: if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==CLIENT_MULTI_STATEMENTS))
240: services._throw("you can't specify together options old_client and multi_statements");
241: if(atoi(value)!=0)
242: client_flag=CLIENT_MULTI_STATEMENTS;
1.35 misha 243: #endif
1.34 misha 244: } else if(strcasecmp(key, "old_client")==0){
1.35 misha 245: #ifdef OLD_MYSQL_CLIENT
246: services._throw("driver was built with old mysql includes so old_client option can't be used");
247: #else
1.34 misha 248: if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==0))
249: services._throw("you can't specify together options old_client and multi_statements");
250: if(atoi(value)!=0)
251: client_flag=0;
1.35 misha 252: #endif
1.2 parser 253: } else
254: services._throw("unknown connect option" /*key*/);
255: } else
256: services._throw("connect option without =value" /*key*/);
257: }
258: }
259: }
260:
1.33 misha 261: if(!mysql_real_connect(
262: connection.handle,
263: host, user, pwd, db,
264: port?port:MYSQL_PORT,
265: unix_socket,
1.34 misha 266: client_flag
1.33 misha 267: )
268: ){
1.14 paf 269: services._throw(mysql_error(connection.handle));
1.33 misha 270: }
1.1 parser 271:
1.33 misha 272: if(charset){
1.41 moko 273: char statement[MAX_STRING+1]="SET CHARACTER SET ";
1.33 misha 274: strncat(statement, charset, MAX_STRING);
275: _exec(connection, statement);
1.1 parser 276: }
277:
1.14 paf 278: if(!connection.autocommit)
1.33 misha 279: _exec(connection, "SET AUTOCOMMIT=0");
1.1 parser 280: }
1.14 paf 281:
282: void disconnect(void *aconnection) {
283: Connection& connection=*static_cast<Connection*>(aconnection);
284: mysql_close(connection.handle);
1.17 paf 285: connection.handle=0;
1.1 parser 286: }
1.32 misha 287:
1.15 paf 288: void commit(void *aconnection) {
1.14 paf 289: Connection& connection=*static_cast<Connection*>(aconnection);
290: if(!connection.autocommit)
1.33 misha 291: _exec(connection, "COMMIT");
1.14 paf 292: }
1.32 misha 293:
1.15 paf 294: void rollback(void *aconnection) {
1.14 paf 295: Connection& connection=*static_cast<Connection*>(aconnection);
296: if(!connection.autocommit)
1.33 misha 297: _exec(connection, "ROLLBACK");
1.14 paf 298: }
299:
1.15 paf 300: bool ping(void *aconnection) {
1.14 paf 301: Connection& connection=*static_cast<Connection*>(aconnection);
302: return mysql_ping(connection.handle)==0;
1.1 parser 303: }
304:
1.37 moko 305: // charset here is services.request_charset(), not connection.client_charset
306: // thus we can't use the sql server quoting support
307: const char* quote(void *aconnection, const char *str, unsigned int length) {
308: const char* from;
309: const char* from_end=str+length;
310:
311: size_t quoted=0;
312:
313: for(from=str; from<from_end; from++){
314: switch (*from) {
315: case 0:
316: case '\n':
317: case '\r':
318: case '\032':
319: case '\\':
320: case '\'':
321: case '"':
322: quoted++;
323: }
324: }
325:
326: if(!quoted)
327: return str;
328:
1.15 paf 329: Connection& connection=*static_cast<Connection*>(aconnection);
1.37 moko 330: char *result=(char*)connection.services->malloc_atomic(length + quoted + 1);
331: char *to = result;
332:
333: for(from=str; from<from_end; from++){
334: char escape;
335: switch (*from) {
336: case 0:
337: escape= '0';
338: break;
339: case '\n':
340: escape= 'n';
341: break;
342: case '\r':
343: escape= 'r';
344: break;
345: case '\032':
346: escape= 'Z';
347: break;
348: case '\\':
349: case '\'':
350: case '"':
351: escape= *from;
352: break;
353: default:
354: *to++=*from;
355: continue;
356: }
357: *to++= '\\';
358: *to++= escape;
359: }
360:
361: *to=0;
1.13 paf 362: return result;
1.1 parser 363: }
1.33 misha 364:
1.24 paf 365: void query(void *aconnection,
1.33 misha 366: const char *astatement,
367: size_t placeholders_count, Placeholder* placeholders,
368: unsigned long offset, unsigned long limit,
369: SQL_Driver_query_event_handlers& handlers
370: ){
1.14 paf 371: Connection& connection=*static_cast<Connection*>(aconnection);
1.15 paf 372: SQL_Driver_services& services=*connection.services;
1.1 parser 373: MYSQL_RES *res=NULL;
1.24 paf 374:
375: if(placeholders_count>0)
376: services._throw("bind variables not supported (yet)");
1.1 parser 377:
1.33 misha 378: bool transcode_needed=_transcode_required(connection);
379:
1.38 misha 380: size_t statement_size=0;
381:
382: if(transcode_needed) {
383: statement_size=strlen(astatement);
384: // transcode query from $request:charset to ?ClientCharset
385: services.transcode(astatement, statement_size,
386: astatement, statement_size,
1.19 paf 387: services.request_charset(),
1.33 misha 388: connection.client_charset);
1.19 paf 389: }
390:
1.1 parser 391: const char *statement;
1.38 misha 392: if(offset || limit!=SQL_NO_LIMIT) {
393: if(!statement_size)
394: statement_size=strlen(astatement);
1.13 paf 395: char *statement_limited=(char *)services.malloc_atomic(
1.33 misha 396: statement_size+MAX_NUMBER*2+8/* LIMIT #,#*/+1);
1.1 parser 397: char *cur=statement_limited;
398: memcpy(cur, astatement, statement_size); cur+=statement_size;
1.33 misha 399: cur+=sprintf(cur, " LIMIT ");
1.1 parser 400: if(offset)
1.42 moko 401: cur+=snprintf(cur, MAX_NUMBER, "%lu,", offset);
1.33 misha 402: if(limit!=SQL_NO_LIMIT)
1.41 moko 403: cur+=snprintf(cur, MAX_NUMBER, "%lu", limit);
1.1 parser 404: statement=statement_limited;
405: } else
406: statement=astatement;
407:
1.14 paf 408: if(mysql_query(connection.handle, statement))
1.33 misha 409: _throw(connection, mysql_error(connection.handle));
1.38 misha 410: if(!(res=mysql_store_result(connection.handle)) && mysql_field_count(connection.handle))
1.33 misha 411: _throw(connection, mysql_error(connection.handle));
1.1 parser 412: if(!res) // empty result: insert|delete|update|...
413: return;
1.38 misha 414:
415: size_t column_count=mysql_num_fields(res);
1.1 parser 416: if(!column_count) // old client
1.14 paf 417: column_count=mysql_field_count(connection.handle);
1.1 parser 418:
1.33 misha 419: if(!column_count){
1.1 parser 420: mysql_free_result(res);
421: services._throw("result contains no columns");
422: }
1.38 misha 423:
1.9 paf 424: bool failed=false;
425: SQL_Error sql_error;
1.38 misha 426:
427: #define CHECK(afailed) \
428: if(afailed) { \
429: failed=true; \
1.9 paf 430: goto cleanup; \
431: }
432:
1.44 moko 433: #define DO_FETCH_FIELDS(transcode_column_name) { \
434: for(size_t i=0; i<column_count; i++) { \
435: if(MYSQL_FIELD *field = mysql_fetch_field(res)){ \
436: size_t length=field->name_length; \
437: const char* str=strdup(services, field->name, length); \
438: transcode_column_name \
439: CHECK(handlers.add_column(sql_error, str, length)); \
440: } else { \
441: /* seen broken client, that reported "44" column count for "select 2+2" */ \
442: column_count=i; \
443: break; \
444: } \
445: } \
446: }
447:
448: #define DO_FETCH_ROWS(transcode_cell_value) { \
449: while(MYSQL_ROW mysql_row=mysql_fetch_row(res)) { \
450: CHECK(handlers.add_row(sql_error)); \
451: unsigned long *lengths=mysql_fetch_lengths(res); \
452: for(size_t i=0; i<column_count; i++) { \
453: const char* str=0; \
454: size_t length=lengths[i]; \
455: if(length) { \
456: str=strdup(services, mysql_row[i], length); \
457: transcode_cell_value \
458: } \
459: CHECK(handlers.add_row_cell(sql_error, str, length)); \
460: } \
461: } \
1.38 misha 462: }
463:
464: bool* transcode_column=0;
465: if(transcode_needed) {
466: transcode_column = new bool[column_count];
467: DO_FETCH_FIELDS(
1.44 moko 468: transcode_column[i] = is_column_transcode_required(field->type);
1.38 misha 469: // transcode column's name from ?ClientCharset to $request:charset
470: services.transcode(str, length,
471: str, length,
472: connection.client_charset,
473: services.request_charset());
474: )
475: CHECK(handlers.before_rows(sql_error));
476: DO_FETCH_ROWS(
477: if(transcode_column[i])
478: // transcode cell's value from ?ClientCharset to $request:charset
1.19 paf 479: services.transcode(str, length,
480: str, length,
1.33 misha 481: connection.client_charset,
1.19 paf 482: services.request_charset());
1.38 misha 483: )
484: } else {
485: // without transcoding
486: DO_FETCH_FIELDS()
487: CHECK(handlers.before_rows(sql_error));
488: DO_FETCH_ROWS()
1.32 misha 489: }
1.9 paf 490: cleanup:
1.38 misha 491: if(transcode_column)
492: delete transcode_column;
1.1 parser 493: mysql_free_result(res);
1.9 paf 494: if(failed)
495: services._throw(sql_error);
1.1 parser 496: }
497:
1.33 misha 498: private:
499: void _exec(Connection& connection, const char* statement) {
500: if(mysql_query(connection.handle, statement))
501: _throw(connection, mysql_error(connection.handle));
502: (*mysql_store_result)(connection.handle); // throw out the result [don't need but must call]
503: }
504:
505: void _throw(Connection& connection, const char* aerr_msg) {
506: size_t length=strlen(aerr_msg);
507: if(length && _transcode_required(connection)) {
508: connection.services->transcode(aerr_msg, length,
509: aerr_msg, length,
510: connection.client_charset,
511: connection.services->request_charset());
512: }
513: connection.services->_throw(aerr_msg);
514: }
515:
516: bool _transcode_required(Connection& connection){
517: return (connection.client_charset && strcmp(connection.client_charset, connection.services->request_charset())!=0);
518: }
519:
1.1 parser 520: private: // mysql client library funcs
521:
1.33 misha 522: typedef MYSQL* (STDCALL *t_mysql_init)(MYSQL *); t_mysql_init mysql_init;
1.1 parser 523:
1.33 misha 524: typedef void (STDCALL *t_mysql_server_end)(); t_mysql_server_end mysql_server_end;
1.29 misha 525:
1.33 misha 526: typedef int (STDCALL *t_mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg); t_mysql_options mysql_options;
1.2 parser 527:
1.1 parser 528: typedef MYSQL_RES* (STDCALL *t_mysql_store_result)(MYSQL *); t_mysql_store_result mysql_store_result;
529:
530: typedef int (STDCALL *t_mysql_query)(MYSQL *, const char *q); t_mysql_query mysql_query;
531:
1.33 misha 532: typedef char* (STDCALL *t_mysql_error)(MYSQL *); t_mysql_error mysql_error;
1.1 parser 533: static char* STDCALL subst_mysql_error(MYSQL *mysql) { return (mysql)->net.last_error; }
534:
1.33 misha 535: typedef MYSQL* (STDCALL *t_mysql_real_connect)(MYSQL *, const char *host,
536: const char *user,
537: const char *passwd,
538: const char *db,
539: unsigned int port,
540: const char *unix_socket,
541: unsigned int clientflag); t_mysql_real_connect mysql_real_connect;
1.1 parser 542:
1.33 misha 543: typedef void (STDCALL *t_mysql_close)(MYSQL *); t_mysql_close mysql_close;
1.1 parser 544:
545: typedef int (STDCALL *t_mysql_ping)(MYSQL *); t_mysql_ping mysql_ping;
546:
547: typedef unsigned long (STDCALL *t_mysql_escape_string)(char *to,const char *from,
1.33 misha 548: unsigned long from_length); t_mysql_escape_string mysql_escape_string;
1.1 parser 549:
1.33 misha 550: typedef void (STDCALL *t_mysql_free_result)(MYSQL_RES *result); t_mysql_free_result mysql_free_result;
1.1 parser 551:
552: typedef unsigned long* (STDCALL *t_mysql_fetch_lengths)(MYSQL_RES *result); t_mysql_fetch_lengths mysql_fetch_lengths;
553:
554: typedef MYSQL_ROW (STDCALL *t_mysql_fetch_row)(MYSQL_RES *result); t_mysql_fetch_row mysql_fetch_row;
555:
1.44 moko 556: typedef MYSQL_FIELD* (STDCALL *t_mysql_fetch_field)(MYSQL_RES *result); t_mysql_fetch_field mysql_fetch_field;
1.1 parser 557:
1.33 misha 558: typedef unsigned int (STDCALL *t_mysql_num_fields)(MYSQL_RES *); t_mysql_num_fields mysql_num_fields;
559: typedef unsigned int (STDCALL *t_mysql_field_count)(MYSQL *); t_mysql_field_count mysql_field_count;
1.1 parser 560:
1.33 misha 561: static unsigned int STDCALL subst_mysql_num_fields(MYSQL_RES *res) { return res->field_count; }
562: static unsigned int STDCALL subst_mysql_field_count(MYSQL *mysql) { return mysql->field_count; }
1.1 parser 563:
564: private: // mysql client library funcs linking
565:
566: const char *dlink(const char *dlopen_file_spec) {
1.43 moko 567: if(lt_dlinit()){
568: if(const char* result=lt_dlerror())
569: return result;
570: return "can not prepare to dynamic loading";
571: }
1.25 paf 572:
1.33 misha 573: lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
574:
575: if(!handle){
576: if(const char* result=lt_dlerror())
577: return result;
1.1 parser 578: return "can not open the dynamic link module";
1.25 paf 579: }
1.1 parser 580:
1.29 misha 581: #define GLINK(name) \
582: name=(t_##name)lt_dlsym(handle, #name);
583:
1.1 parser 584: #define DSLINK(name, action) \
1.29 misha 585: GLINK(name) \
1.1 parser 586: if(!name) \
587: action;
588:
589: #define DLINK(name) DSLINK(name, return "function " #name " was not found")
590: #define SLINK(name) DSLINK(name, name=subst_##name)
591:
592: DLINK(mysql_init);
1.29 misha 593: GLINK(mysql_server_end);
1.2 parser 594: DLINK(mysql_options);
1.1 parser 595: DLINK(mysql_store_result);
596: DLINK(mysql_query);
597: SLINK(mysql_error);
598: DLINK(mysql_real_connect);
599: DLINK(mysql_close);
600: DLINK(mysql_ping);
601: DLINK(mysql_escape_string);
602: DLINK(mysql_free_result);
603: DLINK(mysql_fetch_lengths);
604: DLINK(mysql_fetch_row);
1.44 moko 605: DLINK(mysql_fetch_field);
1.1 parser 606: SLINK(mysql_num_fields);
607: SLINK(mysql_field_count);
608: return 0;
609: }
610:
611: };
612:
613: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
1.29 misha 614: static MySQL_Driver Driver;
615: return &Driver;
1.1 parser 616: }