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