Annotation of sql/mysql/parser3mysql.C, revision 1.37

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

E-mail: