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

1.1       parser      1: /** @file
                      2:        Parser MySQL driver.
                      3: 
                      4:        Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)
                      5: 
                      6:        Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)
                      7: 
                      8:        2001.07.30 using MySQL 3.23.22b
                      9: */
1.2     ! parser     10: static const char *RCSId="$Id: parser3mysql.C,v 1.1.1.1 2001/09/21 15:40:55 parser Exp $"; 
1.1       parser     11: 
                     12: #include "config_includes.h"
                     13: 
                     14: #include "pa_sql_driver.h"
                     15: 
                     16: #define NO_CLIENT_LONG_LONG
                     17: #include "mysql.h"
                     18: #include "ltdl.h"
                     19: 
                     20: #define MAX_STRING 0x400
                     21: #define MAX_NUMBER 20
                     22: 
                     23: #if _MSC_VER
                     24: #      define snprintf _snprintf
1.2     ! parser     25: #      define strcasecmp _stricmp
1.1       parser     26: #endif
                     27: 
                     28: static char *lsplit(char *string, char delim) {
                     29:     if(string) {
                     30:                char *v=strchr(string, delim);
                     31:                if(v) {
                     32:                        *v=0;
                     33:                        return v+1;
                     34:                }
                     35:     }
                     36:     return 0;
                     37: }
                     38: 
1.2     ! parser     39: static char *lsplit(char **string_ref, char delim) {
        !            40:     char *result=*string_ref;
        !            41:        char *next=lsplit(*string_ref, delim);
        !            42:     *string_ref=next;
        !            43:     return result;
        !            44: }
        !            45: 
1.1       parser     46: /**
                     47:        MySQL server driver
                     48: */
                     49: class MySQL_Driver : public SQL_Driver {
                     50: public:
                     51: 
                     52:        MySQL_Driver() : SQL_Driver() {
                     53:        }
                     54: 
                     55:        /// get api version
                     56:        int api_version() { return SQL_DRIVER_API_VERSION; }
                     57:        /// initialize driver by loading sql dynamic link library
                     58:        const char *initialize(const char *dlopen_file_spec) {
                     59:                return dlopen_file_spec?
                     60:                        dlink(dlopen_file_spec):"client library column is empty";
                     61:        }
                     62:        /**     connect
                     63:                @param used_only_in_connect_url
1.2     ! parser     64:                        format: @b user:pass@host[:port]|[/unix/socket]/database?
        !            65:                                charset=cp1251_koi8&
        !            66:                                timeout=3&
        !            67:                                compress=1&
        !            68:                                named_pipe=1
1.1       parser     69:                        3.23.22b
                     70:                        Currently the only option for @b character_set_name is cp1251_koi8.
                     71:                        WARNING: must be used only to connect, for buffer doesn't live long
                     72:        */
                     73:        void connect(
                     74:                char *used_only_in_connect_url, 
                     75:                SQL_Driver_services& services, 
                     76:                void **connection ///< output: MYSQL *
                     77:                ) {
                     78:                char *user=used_only_in_connect_url;
                     79:                char *s=lsplit(user, '@');
                     80:                char *host=0;
                     81:                char *unix_socket=0;
                     82:                if(s && s[0]=='[') { // unix socket
                     83:                        unix_socket=1+s;
                     84:                        s=lsplit(unix_socket, ']');
                     85:                } else { // IP
                     86:                        host=s;
                     87:                }
                     88:                char *db=lsplit(s, '/');
                     89:                char *pwd=lsplit(user, ':');
                     90:                char *error_pos=0;
                     91:                char *port_cstr=lsplit(host, ':');
                     92:                int port=port_cstr?strtol(port_cstr, &error_pos, 0):0;
1.2     ! parser     93:                char *options=lsplit(db, '?');
        !            94: 
        !            95:                char *charset=0;
1.1       parser     96: 
                     97:            MYSQL *mysql=mysql_init(NULL);
1.2     ! parser     98: 
        !            99:                while(options) {
        !           100:                        if(char *key=lsplit(&options, '&')) {
        !           101:                                if(*key) {
        !           102:                                        if(char *value=lsplit(key, '=')) {
        !           103:                                                if(strcasecmp(key, "charset")==0) {
        !           104:                                                        charset=value;
        !           105:                                                } else if(strcasecmp(key, "timeout")==0) {
        !           106:                                                        unsigned int timeout=(unsigned int)atoi(value);
        !           107:                                                        if(mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout)!=0)
        !           108:                                                                services._throw(mysql_error(mysql));
        !           109:                                                } else if(strcasecmp(key, "compress")==0) {
        !           110:                                                        if(atoi(value))
        !           111:                                                                if(mysql_options(mysql, MYSQL_OPT_COMPRESS, 0)!=0)
        !           112:                                                                        services._throw(mysql_error(mysql));
        !           113:                                                } else if(strcasecmp(key, "named_pipe")==0) {
        !           114:                                                        if(atoi(value))
        !           115:                                                                if(mysql_options(mysql, MYSQL_OPT_NAMED_PIPE , 0)!=0)
        !           116:                                                                        services._throw(mysql_error(mysql));
        !           117:                                                } else
        !           118:                                                        services._throw("unknown connect option" /*key*/);
        !           119:                                        } else 
        !           120:                                                services._throw("connect option without =value" /*key*/);
        !           121:                                }
        !           122:                        }
        !           123:                }
        !           124: 
1.1       parser    125:                if(!mysql_real_connect(mysql, 
                    126:                        host, user, pwd, db, port?port:MYSQL_PORT, unix_socket, 0))
                    127:                        services._throw(mysql_error(mysql));
                    128: 
1.2     ! parser    129:                if(charset) {
1.1       parser    130:                        // set charset
                    131:                        char statement[MAX_STRING]="set CHARACTER SET "; // cp1251_koi8
                    132:                        strncat(statement, charset, MAX_STRING);
                    133:                        
                    134:                        if(mysql_query(mysql, statement)) 
                    135:                                services._throw(mysql_error(mysql));
                    136:                        (*mysql_store_result)(mysql); // throw out the result [don't need but must call]
                    137:                }
                    138: 
                    139:                *(MYSQL **)connection=mysql;
                    140:        }
                    141:        void disconnect(void *connection) {
                    142:            mysql_close((MYSQL *)connection);
                    143:        }
                    144:        void commit(SQL_Driver_services&, void *) {}
                    145:        void rollback(SQL_Driver_services&, void *) {}
                    146: 
                    147:        bool ping(SQL_Driver_services&, void *connection) {
                    148:                return mysql_ping((MYSQL *)connection)==0;
                    149:        }
                    150: 
                    151:        unsigned int quote(
                    152:                SQL_Driver_services&, void *connection,
                    153:                char *to, const char *from, unsigned int length) {
                    154:                /*
                    155:                        3.23.22b
                    156:                        You must allocate the to buffer to be at least length*2+1 bytes long. 
                    157:                        (In the worse case, each character may need to be encoded as using two bytes, 
                    158:                        and you need room for the terminating null byte.)
                    159: 
                    160:                        it's already UNTAINT_TIMES_BIGGER
                    161:                */
                    162:                return (*mysql_escape_string)(to, from, length);
                    163:        }
                    164:        void query(
                    165:                SQL_Driver_services& services, void *connection, 
                    166:                const char *astatement, unsigned long offset, unsigned long limit,
                    167:                SQL_Driver_query_event_handlers& handlers) {
                    168: 
                    169:                MYSQL *mysql=(MYSQL *)connection;
                    170:                MYSQL_RES *res=NULL;
                    171: 
                    172:                const char *statement;
                    173:                if(offset || limit) {
                    174:                        size_t statement_size=strlen(astatement);
                    175:                        char *statement_limited=(char *)services.malloc(
                    176:                                statement_size+MAX_NUMBER*2+8/* limit #,#*/+1);
                    177:                        char *cur=statement_limited;
                    178:                        memcpy(cur, astatement, statement_size); cur+=statement_size;
                    179:                        cur+=sprintf(cur, " limit ");
                    180:                        if(offset)
                    181:                                cur+=snprintf(cur, MAX_NUMBER+1, "%u,", offset);
                    182:                        if(limit)
                    183:                                cur+=snprintf(cur, MAX_NUMBER, "%u", limit);
                    184:                        statement=statement_limited;
                    185:                } else
                    186:                        statement=astatement;
                    187: 
                    188:                if(mysql_query(mysql, statement)) 
                    189:                        services._throw(mysql_error(mysql));
                    190:                if(!(res=mysql_store_result(mysql)) && mysql_field_count(mysql)) 
                    191:                        services._throw(mysql_error(mysql));
                    192:                if(!res) // empty result: insert|delete|update|...
                    193:                        return;
                    194:                
                    195:                int column_count=mysql_num_fields(res);
                    196:                if(!column_count) // old client
                    197:                        column_count=mysql_field_count(mysql);
                    198: 
                    199:                if(!column_count) {
                    200:                        mysql_free_result(res);
                    201:                        services._throw("result contains no columns");
                    202:                }
                    203: 
                    204:                for(int i=0; i<column_count; i++){
                    205:                        MYSQL_FIELD *field=mysql_fetch_field(res);
                    206:                        size_t size=strlen(field->name);
                    207:                        void *ptr=services.malloc(size);
                    208:                        memcpy(ptr, field->name, size);
                    209:                        handlers.add_column(ptr, size);
                    210:                }
                    211: 
                    212:                handlers.before_rows();
                    213:                
                    214:                if(unsigned long row_count=(unsigned long)mysql_num_rows(res))
                    215:                        for(unsigned long r=0; r<row_count; r++) 
                    216:                                if(MYSQL_ROW mysql_row=mysql_fetch_row(res)) { // never false..
                    217:                                        handlers.add_row();
                    218:                                        unsigned long *lengths=mysql_fetch_lengths(res);
                    219:                                        for(int i=0; i<column_count; i++){
                    220:                                                size_t size=(size_t)lengths[i];
                    221:                                                void *ptr;
                    222:                                                if(size) {
                    223:                                                        ptr=services.malloc(size);
                    224:                                                        memcpy(ptr, mysql_row[i], size);
                    225:                                                } else
                    226:                                                        ptr=0;
                    227:                                                handlers.add_row_cell(ptr, size);
                    228:                                        }
                    229:                                }
                    230: 
                    231:                mysql_free_result(res);
                    232:        }
                    233: 
                    234: private: // mysql client library funcs
                    235: 
                    236:        typedef MYSQL* (STDCALL *t_mysql_init)(MYSQL *);        t_mysql_init mysql_init;
                    237:        
1.2     ! parser    238:        typedef int (STDCALL *t_mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg); t_mysql_options mysql_options;
        !           239:        
1.1       parser    240:        typedef MYSQL_RES* (STDCALL *t_mysql_store_result)(MYSQL *); t_mysql_store_result mysql_store_result;
                    241:        
                    242:        typedef int             (STDCALL *t_mysql_query)(MYSQL *, const char *q); t_mysql_query mysql_query;
                    243:        
                    244:        typedef char * (STDCALL *t_mysql_error)(MYSQL *); t_mysql_error mysql_error;
                    245:        static char* STDCALL subst_mysql_error(MYSQL *mysql) { return (mysql)->net.last_error; }
                    246: 
                    247:        typedef MYSQL*          (STDCALL *t_mysql_real_connect)(MYSQL *, const char *host,
                    248:                                           const char *user,
                    249:                                           const char *passwd,
                    250:                                           const char *db,
                    251:                                           unsigned int port,
                    252:                                           const char *unix_socket,
                    253:                                           unsigned int clientflag); t_mysql_real_connect mysql_real_connect;
                    254: 
                    255:        typedef void            (STDCALL *t_mysql_close)(MYSQL *); t_mysql_close mysql_close;
                    256:        
                    257:        typedef int             (STDCALL *t_mysql_ping)(MYSQL *); t_mysql_ping mysql_ping;
                    258:        
                    259:        typedef unsigned long   (STDCALL *t_mysql_escape_string)(char *to,const char *from,
                    260:                                            unsigned long from_length); t_mysql_escape_string mysql_escape_string;
                    261:        
                    262:        typedef void            (STDCALL *t_mysql_free_result)(MYSQL_RES *result); t_mysql_free_result mysql_free_result;
                    263:        
                    264:        typedef unsigned long* (STDCALL *t_mysql_fetch_lengths)(MYSQL_RES *result); t_mysql_fetch_lengths mysql_fetch_lengths;
                    265:        
                    266:        typedef MYSQL_ROW       (STDCALL *t_mysql_fetch_row)(MYSQL_RES *result); t_mysql_fetch_row mysql_fetch_row;
                    267:        
                    268:        typedef MYSQL_FIELD*    (STDCALL *t_mysql_fetch_field)(MYSQL_RES *result); t_mysql_fetch_field mysql_fetch_field;
                    269:        
                    270:        typedef my_ulonglong (STDCALL *t_mysql_num_rows)(MYSQL_RES *); t_mysql_num_rows mysql_num_rows;
                    271:        static my_ulonglong STDCALL subst_mysql_num_rows(MYSQL_RES *res) { return res->row_count; }
                    272:        
                    273:        typedef unsigned int (STDCALL *t_mysql_num_fields)(MYSQL_RES *); t_mysql_num_fields mysql_num_fields;
                    274:        static unsigned int STDCALL subst_mysql_num_fields(MYSQL_RES *res) { return res->field_count; }
                    275: 
                    276:        typedef unsigned int (STDCALL *t_mysql_field_count)(MYSQL *); t_mysql_field_count mysql_field_count;
                    277:        static unsigned int STDCALL subst_mysql_field_count(MYSQL *mysql) { return mysql->field_count; }
                    278: 
                    279: private: // mysql client library funcs linking
                    280: 
                    281:        const char *dlink(const char *dlopen_file_spec) {
                    282:         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
                    283:         if (!handle)
                    284:                        return "can not open the dynamic link module";
                    285: 
                    286:                #define DSLINK(name, action) \
                    287:                        name=(t_##name)lt_dlsym(handle, #name); \
                    288:                                if(!name) \
                    289:                                        action;
                    290: 
                    291:                #define DLINK(name) DSLINK(name, return "function " #name " was not found")
                    292:                #define SLINK(name) DSLINK(name, name=subst_##name)
                    293:                
                    294:                DLINK(mysql_init);
1.2     ! parser    295:                DLINK(mysql_options);
1.1       parser    296:                DLINK(mysql_store_result);
                    297:                DLINK(mysql_query);
                    298:                SLINK(mysql_error);
                    299:                DLINK(mysql_real_connect);
                    300:                DLINK(mysql_close);
                    301:                DLINK(mysql_ping);
                    302:                DLINK(mysql_escape_string);
                    303:                DLINK(mysql_free_result);
                    304:                DLINK(mysql_fetch_lengths);
                    305:                DLINK(mysql_fetch_row);
                    306:                DLINK(mysql_fetch_field);
                    307:                SLINK(mysql_num_rows);
                    308:                SLINK(mysql_num_fields);
                    309:                SLINK(mysql_field_count);
                    310:                return 0;
                    311:        }
                    312: 
                    313: };
                    314: 
                    315: extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
                    316:        return new MySQL_Driver();
                    317: }

E-mail: