Diff for /sql/mysql/parser3mysql.C between versions 1.3 and 1.34

version 1.3, 2001/11/08 10:21:23 version 1.34, 2008/06/30 14:00:19
Line 1 Line 1
 /** @file  /** @file
         Parser MySQL driver.          Parser MySQL driver.
   
         Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com)          Copyright(c) 2001, 2003 ArtLebedev Group (http://www.artlebedev.com)
   
         Author: Alexander Petrosyan <paf@design.ru>(http://design.ru/paf)          Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
   
         2001.07.30 using MySQL 3.23.22b          2001.07.30 using MySQL 3.23.22b
   
Line 28  static const char *RCSId="$Id$"; Line 28  static const char *RCSId="$Id$";
 #       define strcasecmp _stricmp  #       define strcasecmp _stricmp
 #endif  #endif
   
 static char *lsplit(char *string, char delim) {  static char *lsplit(char *string, char delim){
     if(string) {          if(string) {
                 char *v=strchr(string, delim);                  if(char *v=strchr(string, delim)){
                 if(v) {  
                         *v=0;                          *v=0;
                         return v+1;                          return v+1;
                 }                  }
     }          }
     return 0;          return 0;
 }  }
   
 static char *lsplit(char **string_ref, char delim) {  static char *lsplit(char **string_ref, char delim){
     char *result=*string_ref;          char *result=*string_ref;
         char *next=lsplit(*string_ref, delim);          char *next=lsplit(*string_ref, delim);
     *string_ref=next;          *string_ref=next;
     return result;          return result;
   }
   
   static char* rsplit(char* string, char delim){
           if(string){
                   if(char* v=strrchr(string, delim)){
                           *v=0;
                           return v+1;
                   }
           }
           return NULL;    
   }
   
   static void toupper_str(char *out, const char *in, size_t size){
           while(size--)
                   *out++=(char)toupper(*in++);
 }  }
   
   struct Connection {
           SQL_Driver_services* services;
   
           MYSQL* handle;
           const char* client_charset;
           bool autocommit;
   };
   
    
 /**  /**
         MySQL server driver          MySQL server driver
 */  */
 class MySQL_Driver : public SQL_Driver {  class MySQL_Driver : public SQL_Driver {
 public:  public:
   
         MySQL_Driver() : SQL_Driver() {          MySQL_Driver() : SQL_Driver() {}
   
           ~MySQL_Driver() {
                   if(mysql_server_end)
                           mysql_server_end();
         }          }
   
         /// get api version          /// get api version
         int api_version() { return SQL_DRIVER_API_VERSION; }          int api_version() { return SQL_DRIVER_API_VERSION; }
   
         /// initialize driver by loading sql dynamic link library          /// initialize driver by loading sql dynamic link library
         const char *initialize(const char *dlopen_file_spec) {          const char *initialize(char *dlopen_file_spec) {
                 return dlopen_file_spec?                  return dlopen_file_spec?
                         dlink(dlopen_file_spec):"client library column is empty";                          dlink(dlopen_file_spec):"client library column is empty";
         }          }
   
         /**     connect          /**     connect
                 @param used_only_in_connect_url                  @param url
                         format: @b user:pass@host[:port]|[/unix/socket]/database?                          format: @b user:pass@host[:port]|[/unix/socket]/database?
                                 charset=cp1251_koi8&                                  charset=value&  // transcode by server with command 'SET CHARACTER SET value'
                                   ClientCharset=charset&  // transcode by parser
                                 timeout=3&                                  timeout=3&
                                 compress=1&                                  compress=0&
                                 named_pipe=1                                  named_pipe=1&
                         3.23.22b                                  autocommit=1&
                         Currently the only option for @b character_set_name is cp1251_koi8.                                  multi_statements=0      // allow more then one statement in one query
                         WARNING: must be used only to connect, for buffer doesn't live long                                  old_client=1            // simulate 3.xx client. not compatible with multi_statements option
                           3.x, 4.0 
                                   only option for charset is cp1251_koi8.
                           4.1+ accept not 'cp1251_koi8' but 'cp1251', 'utf8' and much more
                                   it is usable for transcoding using sql server
         */          */
         void connect(          void connect(
                 char *used_only_in_connect_url,                                   char *url, 
                 SQL_Driver_services& services,                                   SQL_Driver_services& services, 
                 void **connection ///< output: MYSQL *                                  void **connection_ref ///< output: Connection*
                 ) {          ){
                 char *user=used_only_in_connect_url;                  char *user=url;
                 char *s=lsplit(user, '@');                  char *s=rsplit(user, '@');
                 char *host=0;                  char *host=0;
                 char *unix_socket=0;                  char *unix_socket=0;
                 if(s && s[0]=='[') { // unix socket                  if(s && s[0]=='[') { // unix socket
Line 96  public: Line 130  public:
                 char *options=lsplit(db, '?');                  char *options=lsplit(db, '?');
   
                 char *charset=0;                  char *charset=0;
                   int client_flag=CLIENT_MULTI_RESULTS;
   
             MYSQL *mysql=mysql_init(NULL);                  Connection& connection=*(Connection *)services.malloc(sizeof(Connection));
                   *connection_ref=&connection;
                 while(options) {                  connection.services=&services;
                         if(char *key=lsplit(&options, '&')) {                  connection.handle=mysql_init(NULL);
                                 if(*key) {                  connection.client_charset=0;    
                                         if(char *value=lsplit(key, '=')) {                  connection.autocommit=true;
                                                 if(strcasecmp(key, "charset")==0) {  
                   while(options){
                           if(char *key=lsplit(&options, '&')){
                                   if(*key){
                                           if(char *value=lsplit(key, '=')){
                                                   if(strcmp(key, "ClientCharset")==0){ // transcoding with parser
                                                           toupper_str(value, value, strlen(value));
                                                           connection.client_charset=value;
                                                   } else if(strcasecmp(key, "charset")==0){ // transcoding with server
                                                         charset=value;                                                          charset=value;
                                                 } else if(strcasecmp(key, "timeout")==0) {                                                  } else if(strcasecmp(key, "timeout")==0){
                                                         unsigned int timeout=(unsigned int)atoi(value);                                                          unsigned int timeout=(unsigned int)atoi(value);
                                                         if(mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout)!=0)                                                          if(mysql_options(connection.handle, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout)!=0)
                                                                 services._throw(mysql_error(mysql));                                                                  services._throw(mysql_error(connection.handle));
                                                 } else if(strcasecmp(key, "compress")==0) {                                                  } else if(strcasecmp(key, "compress")==0){
                                                         if(atoi(value))                                                          if(atoi(value))
                                                                 if(mysql_options(mysql, MYSQL_OPT_COMPRESS, 0)!=0)                                                                  if(mysql_options(connection.handle, MYSQL_OPT_COMPRESS, 0)!=0)
                                                                         services._throw(mysql_error(mysql));                                                                          services._throw(mysql_error(connection.handle));
                                                 } else if(strcasecmp(key, "named_pipe")==0) {                                                  } else if(strcasecmp(key, "named_pipe")==0){
                                                         if(atoi(value))                                                          if(atoi(value))
                                                                 if(mysql_options(mysql, MYSQL_OPT_NAMED_PIPE , 0)!=0)                                                                  if(mysql_options(connection.handle, MYSQL_OPT_NAMED_PIPE, 0)!=0)
                                                                         services._throw(mysql_error(mysql));                                                                          services._throw(mysql_error(connection.handle));
                                                   } else if(strcasecmp(key, "autocommit")==0){
                                                           if(atoi(value)==0)
                                                                   connection.autocommit=false;
                                                   } else if(strcasecmp(key, "multi_statements")==0){
                                                           if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==CLIENT_MULTI_STATEMENTS))
                                                                   services._throw("you can't specify together options old_client and multi_statements");
                                                           if(atoi(value)!=0)
                                                                   client_flag=CLIENT_MULTI_STATEMENTS;
                                                   } else if(strcasecmp(key, "old_client")==0){
                                                           if(!(client_flag==CLIENT_MULTI_RESULTS || client_flag==0))
                                                                   services._throw("you can't specify together options old_client and multi_statements");
                                                           if(atoi(value)!=0)
                                                                   client_flag=0;
                                                 } else                                                  } else
                                                         services._throw("unknown connect option" /*key*/);                                                          services._throw("unknown connect option" /*key*/);
                                         } else                                           } else 
Line 125  public: Line 181  public:
                         }                          }
                 }                  }
   
                 if(!mysql_real_connect(mysql,                   if(!mysql_real_connect(
                         host, user, pwd, db, port?port:MYSQL_PORT, unix_socket, 0))                                          connection.handle, 
                         services._throw(mysql_error(mysql));                                          host, user, pwd, db,
                                           port?port:MYSQL_PORT,
                 if(charset) {                                          unix_socket,
                         // set charset                                          client_flag
                         char statement[MAX_STRING]="set CHARACTER SET "; // cp1251_koi8                                  )
                   ){
                           services._throw(mysql_error(connection.handle));
                   }
   
                   if(charset){
                           char statement[MAX_STRING]="SET CHARACTER SET ";
                         strncat(statement, charset, MAX_STRING);                          strncat(statement, charset, MAX_STRING);
                                                   _exec(connection, statement);
                         if(mysql_query(mysql, statement))   
                                 services._throw(mysql_error(mysql));  
                         (*mysql_store_result)(mysql); // throw out the result [don't need but must call]  
                 }                  }
   
                 *(MYSQL **)connection=mysql;                  if(!connection.autocommit)
                           _exec(connection, "SET AUTOCOMMIT=0");
           }
   
           void disconnect(void *aconnection) {
                   Connection& connection=*static_cast<Connection*>(aconnection);
                   mysql_close(connection.handle);
                   connection.handle=0;
         }          }
         void disconnect(void *connection) {  
             mysql_close((MYSQL *)connection);          void commit(void *aconnection) {
                   Connection& connection=*static_cast<Connection*>(aconnection);
                   if(!connection.autocommit)
                           _exec(connection, "COMMIT");
           }
   
           void rollback(void *aconnection) {
                   Connection& connection=*static_cast<Connection*>(aconnection);
                   if(!connection.autocommit)
                           _exec(connection, "ROLLBACK");
         }          }
         void commit(SQL_Driver_services&, void *) {}  
         void rollback(SQL_Driver_services&, void *) {}  
   
         bool ping(SQL_Driver_services&, void *connection) {          bool ping(void *aconnection) {
                 return mysql_ping((MYSQL *)connection)==0;                  Connection& connection=*static_cast<Connection*>(aconnection);
                   return mysql_ping(connection.handle)==0;
         }          }
   
         unsigned int quote(          const char* quote(void *aconnection, const char *from, unsigned int length) {
                 SQL_Driver_services&, void *connection,                  Connection& connection=*static_cast<Connection*>(aconnection);
                 char *to, const char *from, unsigned int length) {  
                 /*                  /*
                         3.23.22b                          3.23.22b
                         You must allocate the to buffer to be at least length*2+1 bytes long.                           You must allocate the to buffer to be at least length*2+1 bytes long. 
                         (In the worse case, each character may need to be encoded as using two bytes,                           (In the worse case, each character may need to be encoded as using two bytes, 
                         and you need room for the terminating null byte.)                          and you need room for the terminating null byte.)
   
                         it's already UNTAINT_TIMES_BIGGER  
                 */                  */
                 return (*mysql_escape_string)(to, from, length);                  char *result=(char*)connection.services->malloc_atomic(length*2+1);
                   mysql_escape_string(result, from, length);
                   return result;
         }          }
         void query(  
                 SQL_Driver_services& services, void *connection,   
                 const char *astatement, unsigned long offset, unsigned long limit,  
                 SQL_Driver_query_event_handlers& handlers) {  
   
                 MYSQL *mysql=(MYSQL *)connection;          void query(void *aconnection, 
                                   const char *astatement, 
                                   size_t placeholders_count, Placeholder* placeholders, 
                                   unsigned long offset, unsigned long limit,
                                   SQL_Driver_query_event_handlers& handlers
           ){
                   Connection& connection=*static_cast<Connection*>(aconnection);
                   SQL_Driver_services& services=*connection.services;
                 MYSQL_RES *res=NULL;                  MYSQL_RES *res=NULL;
   
                   if(placeholders_count>0)
                           services._throw("bind variables not supported (yet)");
   
                   bool transcode_needed=_transcode_required(connection);
   
                   // transcode query from $request:charset to ?ClientCharset
                   if(transcode_needed){
                           size_t length=strlen(astatement);
                           services.transcode(astatement, length,
                                   astatement, length,
                                   services.request_charset(),
                                   connection.client_charset);
                   }
   
                 const char *statement;                  const char *statement;
                 if(offset || limit) {                  if(offset || limit!=SQL_NO_LIMIT){
                         size_t statement_size=strlen(astatement);                          size_t statement_size=strlen(astatement);
                         char *statement_limited=(char *)services.malloc(                          char *statement_limited=(char *)services.malloc_atomic(
                                 statement_size+MAX_NUMBER*2+8/* limit #,#*/+1);                                  statement_size+MAX_NUMBER*2+8/* LIMIT #,#*/+1);
                         char *cur=statement_limited;                          char *cur=statement_limited;
                         memcpy(cur, astatement, statement_size); cur+=statement_size;                          memcpy(cur, astatement, statement_size); cur+=statement_size;
                         cur+=sprintf(cur, " limit ");                          cur+=sprintf(cur, " LIMIT ");
                         if(offset)                          if(offset)
                                 cur+=snprintf(cur, MAX_NUMBER+1, "%u,", offset);                                  cur+=snprintf(cur, MAX_NUMBER+1, "%u,", offset);
                         if(limit)                          if(limit!=SQL_NO_LIMIT)
                                 cur+=snprintf(cur, MAX_NUMBER, "%u", limit);                                  cur+=snprintf(cur, MAX_NUMBER, "%u", limit);
                         statement=statement_limited;                          statement=statement_limited;
                 } else                  } else
                         statement=astatement;                          statement=astatement;
   
                 if(mysql_query(mysql, statement))                   if(mysql_query(connection.handle, statement)) 
                         services._throw(mysql_error(mysql));                          _throw(connection, mysql_error(connection.handle));
                 if(!(res=mysql_store_result(mysql)) && mysql_field_count(mysql))                   if(!(res=mysql_store_result(connection.handle)) && mysql_field_count(connection.handle)) 
                         services._throw(mysql_error(mysql));                          _throw(connection, mysql_error(connection.handle));
                 if(!res) // empty result: insert|delete|update|...                  if(!res) // empty result: insert|delete|update|...
                         return;                          return;
                                   
                 int column_count=mysql_num_fields(res);                  int column_count=mysql_num_fields(res);
                 if(!column_count) // old client                  if(!column_count) // old client
                         column_count=mysql_field_count(mysql);                          column_count=mysql_field_count(connection.handle);
   
                 if(!column_count) {                  if(!column_count){
                         mysql_free_result(res);                          mysql_free_result(res);
                         services._throw("result contains no columns");                          services._throw("result contains no columns");
                 }                  }
                   
                   bool failed=false;
                   SQL_Error sql_error;
   #define CHECK(afailed) \
                   if(afailed) { \
                           failed=true; \
                           goto cleanup; \
                   }
   
                 for(int i=0; i<column_count; i++){                  for(int i=0; i<column_count; i++){
                         MYSQL_FIELD *field=mysql_fetch_field(res);                          if(MYSQL_FIELD *field=mysql_fetch_field(res)){
                         size_t size=strlen(field->name);                                  size_t length=strlen(field->name);
                         void *ptr=services.malloc(size);                                  char* strm=(char*)services.malloc_atomic(length+1);
                         memcpy(ptr, field->name, size);                                  memcpy(strm, field->name, length+1);
                         handlers.add_column(ptr, size);                                  const char* str=strm;
   
                                   // transcode column name from ?ClientCharset to $request:charset 
                                   if(transcode_needed){
                                           services.transcode(str, length,
                                                   str, length,
                                                   connection.client_charset,
                                                   services.request_charset());
                                   }
                                   
                                   CHECK(handlers.add_column(sql_error, str, length));
                           } else {
                                   // seen some broken client, 
                                   // which reported "44" for column count of response to "select 2+2"
                                   column_count=i;
                                   break;
                           }
                 }                  }
   
                 handlers.before_rows();                  CHECK(handlers.before_rows(sql_error));
                                   
                 while(MYSQL_ROW mysql_row=mysql_fetch_row(res)) {                  while(MYSQL_ROW mysql_row=mysql_fetch_row(res)){
                         handlers.add_row();                          CHECK(handlers.add_row(sql_error));
                         unsigned long *lengths=mysql_fetch_lengths(res);                          unsigned long *lengths=mysql_fetch_lengths(res);
                         for(int i=0; i<column_count; i++){                          for(int i=0; i<column_count; i++){
                                 size_t size=(size_t)lengths[i];                                  size_t length=(size_t)lengths[i];
                                 void *ptr;                                  const char* str;
                                 if(size) {                                  if(length){
                                         ptr=services.malloc(size);                                          char *strm=(char*)services.malloc_atomic(length+1);
                                         memcpy(ptr, mysql_row[i], size);                                          memcpy(strm, mysql_row[i], length);
                                 } else                                          strm[length]=0;
                                         ptr=0;                                          str=strm;
                                 handlers.add_row_cell(ptr, size);  
                         }                                          // transcode cell value from ?ClientCharset to $request:charset
                 }                                          if(transcode_needed)
                                                   services.transcode(str, length,
                                                           str, length,
                                                           connection.client_charset,
                                                           services.request_charset());
                                   } else
                                           str=0;
                                   CHECK(handlers.add_row_cell(sql_error, str, length));
                           }
                   }
   cleanup:
                 mysql_free_result(res);                  mysql_free_result(res);
                   if(failed)
                           services._throw(sql_error);
           }
   
   private:
           void _exec(Connection& connection, const char* statement) {
                   if(mysql_query(connection.handle, statement)) 
                           _throw(connection, mysql_error(connection.handle));
                   (*mysql_store_result)(connection.handle); // throw out the result [don't need but must call]
           }
   
           void _throw(Connection& connection, const char* aerr_msg) {
                   size_t length=strlen(aerr_msg);
                   if(length && _transcode_required(connection)) {
                           connection.services->transcode(aerr_msg, length,
                                   aerr_msg, length,
                                   connection.client_charset,
                                   connection.services->request_charset());
                   }
                   connection.services->_throw(aerr_msg);
           }
   
           bool _transcode_required(Connection& connection){
                   return (connection.client_charset && strcmp(connection.client_charset, connection.services->request_charset())!=0);
         }          }
   
 private: // mysql client library funcs  private: // mysql client library funcs
   
         typedef MYSQL* (STDCALL *t_mysql_init)(MYSQL *);        t_mysql_init mysql_init;          typedef MYSQL*  (STDCALL *t_mysql_init)(MYSQL *);       t_mysql_init mysql_init;
                   
         typedef int (STDCALL *t_mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg); t_mysql_options mysql_options;          typedef void    (STDCALL *t_mysql_server_end)();        t_mysql_server_end mysql_server_end;
   
           typedef int             (STDCALL *t_mysql_options)(MYSQL *mysql, enum mysql_option option, const char *arg); t_mysql_options mysql_options;
                   
         typedef MYSQL_RES* (STDCALL *t_mysql_store_result)(MYSQL *); t_mysql_store_result mysql_store_result;          typedef MYSQL_RES* (STDCALL *t_mysql_store_result)(MYSQL *); t_mysql_store_result mysql_store_result;
                   
         typedef int             (STDCALL *t_mysql_query)(MYSQL *, const char *q); t_mysql_query mysql_query;          typedef int             (STDCALL *t_mysql_query)(MYSQL *, const char *q); t_mysql_query mysql_query;
                   
         typedef char * (STDCALL *t_mysql_error)(MYSQL *); t_mysql_error mysql_error;          typedef char*   (STDCALL *t_mysql_error)(MYSQL *); t_mysql_error mysql_error;
         static char* STDCALL subst_mysql_error(MYSQL *mysql) { return (mysql)->net.last_error; }          static char* STDCALL subst_mysql_error(MYSQL *mysql) { return (mysql)->net.last_error; }
   
         typedef MYSQL*          (STDCALL *t_mysql_real_connect)(MYSQL *, const char *host,          typedef MYSQL*  (STDCALL *t_mysql_real_connect)(MYSQL *, const char *host,
                                            const char *user,                                                  const char *user,
                                            const char *passwd,                                                  const char *passwd,
                                            const char *db,                                                  const char *db,
                                            unsigned int port,                                                  unsigned int port,
                                            const char *unix_socket,                                                  const char *unix_socket,
                                            unsigned int clientflag); t_mysql_real_connect mysql_real_connect;                                                  unsigned int clientflag); t_mysql_real_connect mysql_real_connect;
   
         typedef void            (STDCALL *t_mysql_close)(MYSQL *); t_mysql_close mysql_close;          typedef void    (STDCALL *t_mysql_close)(MYSQL *); t_mysql_close mysql_close;
                   
         typedef int             (STDCALL *t_mysql_ping)(MYSQL *); t_mysql_ping mysql_ping;          typedef int             (STDCALL *t_mysql_ping)(MYSQL *); t_mysql_ping mysql_ping;
                   
         typedef unsigned long   (STDCALL *t_mysql_escape_string)(char *to,const char *from,          typedef unsigned long   (STDCALL *t_mysql_escape_string)(char *to,const char *from,
                                             unsigned long from_length); t_mysql_escape_string mysql_escape_string;                                                  unsigned long from_length); t_mysql_escape_string mysql_escape_string;
                   
         typedef void            (STDCALL *t_mysql_free_result)(MYSQL_RES *result); t_mysql_free_result mysql_free_result;          typedef void    (STDCALL *t_mysql_free_result)(MYSQL_RES *result); t_mysql_free_result mysql_free_result;
                   
         typedef unsigned long* (STDCALL *t_mysql_fetch_lengths)(MYSQL_RES *result); t_mysql_fetch_lengths mysql_fetch_lengths;          typedef unsigned long* (STDCALL *t_mysql_fetch_lengths)(MYSQL_RES *result); t_mysql_fetch_lengths mysql_fetch_lengths;
                   
Line 268  private: // mysql client library funcs Line 417  private: // mysql client library funcs
                   
         typedef MYSQL_FIELD*    (STDCALL *t_mysql_fetch_field)(MYSQL_RES *result); t_mysql_fetch_field mysql_fetch_field;          typedef MYSQL_FIELD*    (STDCALL *t_mysql_fetch_field)(MYSQL_RES *result); t_mysql_fetch_field mysql_fetch_field;
                   
         typedef unsigned int (STDCALL *t_mysql_num_fields)(MYSQL_RES *); t_mysql_num_fields mysql_num_fields;          typedef unsigned int    (STDCALL *t_mysql_num_fields)(MYSQL_RES *); t_mysql_num_fields mysql_num_fields;
         static unsigned int STDCALL subst_mysql_num_fields(MYSQL_RES *res) { return res->field_count; }          typedef unsigned int    (STDCALL *t_mysql_field_count)(MYSQL *); t_mysql_field_count mysql_field_count;
   
         typedef unsigned int (STDCALL *t_mysql_field_count)(MYSQL *); t_mysql_field_count mysql_field_count;          static unsigned int     STDCALL subst_mysql_num_fields(MYSQL_RES *res) { return res->field_count; }
         static unsigned int STDCALL subst_mysql_field_count(MYSQL *mysql) { return mysql->field_count; }          static unsigned int     STDCALL subst_mysql_field_count(MYSQL *mysql) { return mysql->field_count; }
   
 private: // mysql client library funcs linking  private: // mysql client library funcs linking
   
         const char *dlink(const char *dlopen_file_spec) {          const char *dlink(const char *dlopen_file_spec) {
         lt_dlhandle handle=lt_dlopen(dlopen_file_spec);                  if(lt_dlinit())
         if (!handle)                          return lt_dlerror();
   
                   lt_dlhandle handle=lt_dlopen(dlopen_file_spec);
   
                   if(!handle){
                           if(const char* result=lt_dlerror())
                                   return result;
                         return "can not open the dynamic link module";                          return "can not open the dynamic link module";
                   }
   
                   #define GLINK(name) \
                           name=(t_##name)lt_dlsym(handle, #name);
   
                 #define DSLINK(name, action) \                  #define DSLINK(name, action) \
                         name=(t_##name)lt_dlsym(handle, #name); \                          GLINK(name) \
                                 if(!name) \                                  if(!name) \
                                         action;                                          action;
   
Line 290  private: // mysql client library funcs l Line 449  private: // mysql client library funcs l
                 #define SLINK(name) DSLINK(name, name=subst_##name)                  #define SLINK(name) DSLINK(name, name=subst_##name)
                                   
                 DLINK(mysql_init);                  DLINK(mysql_init);
                   GLINK(mysql_server_end);
                 DLINK(mysql_options);                  DLINK(mysql_options);
                 DLINK(mysql_store_result);                  DLINK(mysql_store_result);
                 DLINK(mysql_query);                  DLINK(mysql_query);
Line 310  private: // mysql client library funcs l Line 470  private: // mysql client library funcs l
 };  };
   
 extern "C" SQL_Driver *SQL_DRIVER_CREATE() {  extern "C" SQL_Driver *SQL_DRIVER_CREATE() {
         return new MySQL_Driver();          static MySQL_Driver Driver;
           return &Driver;
 }  }

Removed from v.1.3  
changed lines
  Added in v.1.34


E-mail: