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

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

E-mail: