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

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

E-mail: