Annotation of sql/mysql/parser3mysql.C, revision 1.38
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.38 ! misha 13: static const char *RCSId="$Id: parser3mysql.C,v 1.37 2010-10-18 21:48:22 moko 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.32 misha 223: } else if(strcasecmp(key, "autocommit")==0){
1.31 misha 224: if(atoi(value)==0)
1.14 paf 225: connection.autocommit=false;
1.34 misha 226: } else if(strcasecmp(key, "multi_statements")==0){
1.35 misha 227: #ifdef OLD_MYSQL_CLIENT
228: services._throw("driver was built with old mysql includes so multi_statements option can't be used");
229: #else
1.34 misha 230: if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==CLIENT_MULTI_STATEMENTS))
231: services._throw("you can't specify together options old_client and multi_statements");
232: if(atoi(value)!=0)
233: client_flag=CLIENT_MULTI_STATEMENTS;
1.35 misha 234: #endif
1.34 misha 235: } else if(strcasecmp(key, "old_client")==0){
1.35 misha 236: #ifdef OLD_MYSQL_CLIENT
237: services._throw("driver was built with old mysql includes so old_client option can't be used");
238: #else
1.34 misha 239: if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==0))
240: services._throw("you can't specify together options old_client and multi_statements");
241: if(atoi(value)!=0)
242: client_flag=0;
1.35 misha 243: #endif
1.2 parser 244: } else
245: services._throw("unknown connect option" /*key*/);
246: } else
247: services._throw("connect option without =value" /*key*/);
248: }
249: }
250: }
251:
1.33 misha 252: if(!mysql_real_connect(
253: connection.handle,
254: host, user, pwd, db,
255: port?port:MYSQL_PORT,
256: unix_socket,
1.34 misha 257: client_flag
1.33 misha 258: )
259: ){
1.14 paf 260: services._throw(mysql_error(connection.handle));
1.33 misha 261: }
1.1 parser 262:
1.33 misha 263: if(charset){
1.32 misha 264: char statement[MAX_STRING]="SET CHARACTER SET ";
1.33 misha 265: strncat(statement, charset, MAX_STRING);
266: _exec(connection, statement);
1.1 parser 267: }
268:
1.14 paf 269: if(!connection.autocommit)
1.33 misha 270: _exec(connection, "SET AUTOCOMMIT=0");
1.1 parser 271: }
1.14 paf 272:
273: void disconnect(void *aconnection) {
274: Connection& connection=*static_cast<Connection*>(aconnection);
275: mysql_close(connection.handle);
1.17 paf 276: connection.handle=0;
1.1 parser 277: }
1.32 misha 278:
1.15 paf 279: void commit(void *aconnection) {
1.14 paf 280: Connection& connection=*static_cast<Connection*>(aconnection);
281: if(!connection.autocommit)
1.33 misha 282: _exec(connection, "COMMIT");
1.14 paf 283: }
1.32 misha 284:
1.15 paf 285: void rollback(void *aconnection) {
1.14 paf 286: Connection& connection=*static_cast<Connection*>(aconnection);
287: if(!connection.autocommit)
1.33 misha 288: _exec(connection, "ROLLBACK");
1.14 paf 289: }
290:
1.15 paf 291: bool ping(void *aconnection) {
1.14 paf 292: Connection& connection=*static_cast<Connection*>(aconnection);
293: return mysql_ping(connection.handle)==0;
1.1 parser 294: }
295:
1.37 moko 296: // charset here is services.request_charset(), not connection.client_charset
297: // thus we can't use the sql server quoting support
298: const char* quote(void *aconnection, const char *str, unsigned int length) {
299: const char* from;
300: const char* from_end=str+length;
301:
302: size_t quoted=0;
303:
304: for(from=str; from<from_end; from++){
305: switch (*from) {
306: case 0:
307: case '\n':
308: case '\r':
309: case '\032':
310: case '\\':
311: case '\'':
312: case '"':
313: quoted++;
314: }
315: }
316:
317: if(!quoted)
318: return str;
319:
1.15 paf 320: Connection& connection=*static_cast<Connection*>(aconnection);
1.37 moko 321: char *result=(char*)connection.services->malloc_atomic(length + quoted + 1);
322: char *to = result;
323:
324: for(from=str; from<from_end; from++){
325: char escape;
326: switch (*from) {
327: case 0:
328: escape= '0';
329: break;
330: case '\n':
331: escape= 'n';
332: break;
333: case '\r':
334: escape= 'r';
335: break;
336: case '\032':
337: escape= 'Z';
338: break;
339: case '\\':
340: case '\'':
341: case '"':
342: escape= *from;
343: break;
344: default:
345: *to++=*from;
346: continue;
347: }
348: *to++= '\\';
349: *to++= escape;
350: }
351:
352: *to=0;
1.13 paf 353: return result;
1.1 parser 354: }
1.33 misha 355:
1.24 paf 356: void query(void *aconnection,
1.33 misha 357: const char *astatement,
358: size_t placeholders_count, Placeholder* placeholders,
359: unsigned long offset, unsigned long limit,
360: SQL_Driver_query_event_handlers& handlers
361: ){
1.14 paf 362: Connection& connection=*static_cast<Connection*>(aconnection);
1.15 paf 363: SQL_Driver_services& services=*connection.services;
1.1 parser 364: MYSQL_RES *res=NULL;
1.24 paf 365:
366: if(placeholders_count>0)
367: services._throw("bind variables not supported (yet)");
1.1 parser 368:
1.33 misha 369: bool transcode_needed=_transcode_required(connection);
370:
1.38 ! misha 371: size_t statement_size=0;
! 372:
! 373: if(transcode_needed) {
! 374: statement_size=strlen(astatement);
! 375: // transcode query from $request:charset to ?ClientCharset
! 376: services.transcode(astatement, statement_size,
! 377: astatement, statement_size,
1.19 paf 378: services.request_charset(),
1.33 misha 379: connection.client_charset);
1.19 paf 380: }
381:
1.1 parser 382: const char *statement;
1.38 ! misha 383: if(offset || limit!=SQL_NO_LIMIT) {
! 384: if(!statement_size)
! 385: statement_size=strlen(astatement);
1.13 paf 386: char *statement_limited=(char *)services.malloc_atomic(
1.33 misha 387: statement_size+MAX_NUMBER*2+8/* LIMIT #,#*/+1);
1.1 parser 388: char *cur=statement_limited;
389: memcpy(cur, astatement, statement_size); cur+=statement_size;
1.33 misha 390: cur+=sprintf(cur, " LIMIT ");
1.1 parser 391: if(offset)
392: cur+=snprintf(cur, MAX_NUMBER+1, "%u,", offset);
1.33 misha 393: if(limit!=SQL_NO_LIMIT)
1.1 parser 394: cur+=snprintf(cur, MAX_NUMBER, "%u", limit);
395: statement=statement_limited;
396: } else
397: statement=astatement;
398:
1.14 paf 399: if(mysql_query(connection.handle, statement))
1.33 misha 400: _throw(connection, mysql_error(connection.handle));
1.38 ! misha 401: if(!(res=mysql_store_result(connection.handle)) && mysql_field_count(connection.handle))
1.33 misha 402: _throw(connection, mysql_error(connection.handle));
1.1 parser 403: if(!res) // empty result: insert|delete|update|...
404: return;
1.38 ! misha 405:
! 406: size_t column_count=mysql_num_fields(res);
1.1 parser 407: if(!column_count) // old client
1.14 paf 408: column_count=mysql_field_count(connection.handle);
1.1 parser 409:
1.33 misha 410: if(!column_count){
1.1 parser 411: mysql_free_result(res);
412: services._throw("result contains no columns");
413: }
1.38 ! misha 414:
1.9 paf 415: bool failed=false;
416: SQL_Error sql_error;
1.38 ! misha 417:
! 418: #define CHECK(afailed) \
! 419: if(afailed) { \
! 420: failed=true; \
1.9 paf 421: goto cleanup; \
422: }
423:
1.38 ! misha 424: #define DO_FETCH_FIELDS(transcode_column_name) { \
! 425: MYSQL_FIELD *fields = mysql_fetch_fields(res); \
! 426: for(size_t i=0; i<column_count; i++) { \
! 427: size_t length=fields[i].name_length; \
! 428: const char* str=strdup(services, fields[i].name, length); \
! 429: transcode_column_name \
! 430: CHECK(handlers.add_column(sql_error, str, length)); \
! 431: } \
! 432: }
! 433:
! 434: #define DO_FETCH_ROWS(transcode_cell_value) { \
! 435: while(MYSQL_ROW mysql_row=mysql_fetch_row(res)) { \
! 436: CHECK(handlers.add_row(sql_error)); \
! 437: unsigned long *lengths=mysql_fetch_lengths(res); \
! 438: for(size_t i=0; i<column_count; i++) { \
! 439: const char* str=0; \
! 440: size_t length=lengths[i]; \
! 441: if(length) { \
! 442: str=strdup(services, mysql_row[i], length); \
! 443: transcode_cell_value \
! 444: } \
! 445: CHECK(handlers.add_row_cell(sql_error, str, length)); \
! 446: } \
! 447: } \
! 448: }
! 449:
! 450: bool* transcode_column=0;
! 451: if(transcode_needed) {
! 452: transcode_column = new bool[column_count];
! 453: DO_FETCH_FIELDS(
! 454: transcode_column[i] = is_column_transcode_required(fields[i].type);
! 455: // transcode column's name from ?ClientCharset to $request:charset
! 456: services.transcode(str, length,
! 457: str, length,
! 458: connection.client_charset,
! 459: services.request_charset());
! 460: )
! 461: CHECK(handlers.before_rows(sql_error));
! 462: DO_FETCH_ROWS(
! 463: if(transcode_column[i])
! 464: // transcode cell's value from ?ClientCharset to $request:charset
1.19 paf 465: services.transcode(str, length,
466: str, length,
1.33 misha 467: connection.client_charset,
1.19 paf 468: services.request_charset());
1.38 ! misha 469: )
! 470: } else {
! 471: // without transcoding
! 472: DO_FETCH_FIELDS()
! 473: CHECK(handlers.before_rows(sql_error));
! 474: DO_FETCH_ROWS()
1.32 misha 475: }
1.9 paf 476: cleanup:
1.38 ! misha 477: if(transcode_column)
! 478: delete transcode_column;
1.1 parser 479: mysql_free_result(res);
1.9 paf 480: if(failed)
481: services._throw(sql_error);
1.1 parser 482: }
483:
1.33 misha 484: private:
485: void _exec(Connection& connection, const char* statement) {
486: if(mysql_query(connection.handle, statement))
487: _throw(connection, mysql_error(connection.handle));
488: (*mysql_store_result)(connection.handle); // throw out the result [don't need but must call]
489: }
490:
491: void _throw(Connection& connection, const char* aerr_msg) {
492: size_t length=strlen(aerr_msg);
493: if(length && _transcode_required(connection)) {
494: connection.services->transcode(aerr_msg, length,
495: aerr_msg, length,
496: connection.client_charset,
497: connection.services->request_charset());
498: }
499: connection.services->_throw(aerr_msg);
500: }
501:
502: bool _transcode_required(Connection& connection){
503: return (connection.client_charset && strcmp(connection.client_charset, connection.services->request_charset())!=0);
504: }
505:
1.1 parser 506: private: // mysql client library funcs
507:
1.33 misha 508: typedef MYSQL* (STDCALL *t_mysql_init)(MYSQL *); t_mysql_init mysql_init;
1.1 parser 509:
1.33 misha 510: typedef void (STDCALL *t_mysql_server_end)(); t_mysql_server_end mysql_server_end;
1.29 misha 511:
1.33 misha 512: typedef int (STDCALL *t_mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg); t_mysql_options mysql_options;
1.2 parser 513:
1.1 parser 514: typedef MYSQL_RES* (STDCALL *t_mysql_store_result)(MYSQL *); t_mysql_store_result mysql_store_result;
515:
516: typedef int (STDCALL *t_mysql_query)(MYSQL *, const char *q); t_mysql_query mysql_query;
517:
1.33 misha 518: typedef char* (STDCALL *t_mysql_error)(MYSQL *); t_mysql_error mysql_error;
1.1 parser 519: static char* STDCALL subst_mysql_error(MYSQL *mysql) { return (mysql)->net.last_error; }
520:
1.33 misha 521: typedef MYSQL* (STDCALL *t_mysql_real_connect)(MYSQL *, const char *host,
522: const char *user,
523: const char *passwd,
524: const char *db,
525: unsigned int port,
526: const char *unix_socket,
527: unsigned int clientflag); t_mysql_real_connect mysql_real_connect;
1.1 parser 528:
1.33 misha 529: typedef void (STDCALL *t_mysql_close)(MYSQL *); t_mysql_close mysql_close;
1.1 parser 530:
531: typedef int (STDCALL *t_mysql_ping)(MYSQL *); t_mysql_ping mysql_ping;
532:
533: typedef unsigned long (STDCALL *t_mysql_escape_string)(char *to,const char *from,
1.33 misha 534: unsigned long from_length); t_mysql_escape_string mysql_escape_string;
1.1 parser 535:
1.33 misha 536: typedef void (STDCALL *t_mysql_free_result)(MYSQL_RES *result); t_mysql_free_result mysql_free_result;
1.1 parser 537:
538: typedef unsigned long* (STDCALL *t_mysql_fetch_lengths)(MYSQL_RES *result); t_mysql_fetch_lengths mysql_fetch_lengths;
539:
540: typedef MYSQL_ROW (STDCALL *t_mysql_fetch_row)(MYSQL_RES *result); t_mysql_fetch_row mysql_fetch_row;
541:
1.38 ! misha 542: typedef MYSQL_FIELD* (STDCALL *t_mysql_fetch_fields)(MYSQL_RES *result); t_mysql_fetch_fields mysql_fetch_fields;
1.1 parser 543:
1.33 misha 544: typedef unsigned int (STDCALL *t_mysql_num_fields)(MYSQL_RES *); t_mysql_num_fields mysql_num_fields;
545: typedef unsigned int (STDCALL *t_mysql_field_count)(MYSQL *); t_mysql_field_count mysql_field_count;
1.1 parser 546:
1.33 misha 547: static unsigned int STDCALL subst_mysql_num_fields(MYSQL_RES *res) { return res->field_count; }
548: static unsigned int STDCALL subst_mysql_field_count(MYSQL *mysql) { return mysql->field_count; }
1.1 parser 549:
550: private: // mysql client library funcs linking
551:
552: const char *dlink(const char *dlopen_file_spec) {
1.10 paf 553: if(lt_dlinit())
554: return lt_dlerror();
1.25 paf 555:
1.33 misha 556: lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
557:
558: if(!handle){
559: if(const char* result=lt_dlerror())
560: return result;
1.1 parser 561: return "can not open the dynamic link module";
1.25 paf 562: }
1.1 parser 563:
1.29 misha 564: #define GLINK(name) \
565: name=(t_##name)lt_dlsym(handle, #name);
566:
1.1 parser 567: #define DSLINK(name, action) \
1.29 misha 568: GLINK(name) \
1.1 parser 569: if(!name) \
570: action;
571:
572: #define DLINK(name) DSLINK(name, return "function " #name " was not found")
573: #define SLINK(name) DSLINK(name, name=subst_##name)
574:
575: DLINK(mysql_init);
1.29 misha 576: GLINK(mysql_server_end);
1.2 parser 577: DLINK(mysql_options);
1.1 parser 578: DLINK(mysql_store_result);
579: DLINK(mysql_query);
580: SLINK(mysql_error);
581: DLINK(mysql_real_connect);
582: DLINK(mysql_close);
583: DLINK(mysql_ping);
584: DLINK(mysql_escape_string);
585: DLINK(mysql_free_result);
586: DLINK(mysql_fetch_lengths);
587: DLINK(mysql_fetch_row);
1.38 ! misha 588: DLINK(mysql_fetch_fields);
1.1 parser 589: SLINK(mysql_num_fields);
590: SLINK(mysql_field_count);
591: return 0;
592: }
593:
594: };
595:
596: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
1.29 misha 597: static MySQL_Driver Driver;
598: return &Driver;
1.1 parser 599: }
E-mail: