--- sql/mysql/parser3mysql.C 2004/01/30 07:30:40 1.18 +++ sql/mysql/parser3mysql.C 2008/05/04 08:29:46 1.31 @@ -10,7 +10,7 @@ 2001.11.06 numrows on "HP-UX istok1 B.11.00 A 9000/869 448594332 two-user license" 3.23.42 & 4.0.0.alfa never worked, both subst & .sl version returned 0 */ -static const char *RCSId="$Id: parser3mysql.C,v 1.18 2004/01/30 07:30:40 paf Exp $"; +static const char *RCSId="$Id: parser3mysql.C,v 1.31 2008/05/04 08:29:46 misha Exp $"; #include "config_includes.h" @@ -46,20 +46,43 @@ static char *lsplit(char **string_ref, c return result; } +static char* rsplit(char* string, char delim) { + if(string) { + char* v=strrchr(string, delim); + if(v) { + *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* cstrClientCharset; bool autocommit; + bool multi_statements; }; + /** MySQL server driver */ class MySQL_Driver : public SQL_Driver { public: - MySQL_Driver() : SQL_Driver() { + MySQL_Driver() : SQL_Driver() {} + + ~MySQL_Driver() { + if(mysql_server_end) + mysql_server_end(); } /// get api version @@ -70,23 +93,25 @@ public: dlink(dlopen_file_spec):"client library column is empty"; } /** connect - @param used_only_in_connect_url + @param url format: @b user:pass@host[:port]|[/unix/socket]/database? charset=cp1251_koi8& timeout=3& compress=1& named_pipe=1 3.23.22b - Currently the only option for @b character_set_name is cp1251_koi8. - WARNING: must be used only to connect, for buffer doesn't live long + Currently the only option for @b character_set_name is cp1251_koi8. + WARNING: must be used only to connect, for buffer doesn't live long + 4.1+ accept not only 'cp1251_koi8' but 'cp1251', 'utf8' and much more + it can be usable for transcoding using sql server */ void connect( - char *used_only_in_connect_url, + char *url, SQL_Driver_services& services, void **connection_ref ///< output: Connection* ) { - char *user=used_only_in_connect_url; - char *s=lsplit(user, '@'); + char *user=url; + char *s=rsplit(user, '@'); char *host=0; char *unix_socket=0; if(s && s[0]=='[') { // unix socket @@ -102,20 +127,25 @@ public: int port=port_cstr?strtol(port_cstr, &error_pos, 0):0; char *options=lsplit(db, '?'); - char *charset=0; + char *cstrBackwardCompAskServerToTranscode=0; Connection& connection=*(Connection *)services.malloc(sizeof(Connection)); connection.services=&services; connection.handle=mysql_init(NULL); + connection.cstrClientCharset=0; connection.autocommit=true; + connection.multi_statements=false; *connection_ref=&connection; while(options) { if(char *key=lsplit(&options, '&')) { if(*key) { if(char *value=lsplit(key, '=')) { - if(strcasecmp(key, "charset")==0) { - charset=value; + if(strcmp(key, "ClientCharset" ) == 0) { // transcoding with parser + toupper_str(value, value, strlen(value)); + connection.cstrClientCharset=value; + } else if(strcasecmp(key, "charset")==0) { // transcoding with mysql server + cstrBackwardCompAskServerToTranscode=value; } else if(strcasecmp(key, "timeout")==0) { unsigned int timeout=(unsigned int)atoi(value); if(mysql_options(connection.handle, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&timeout)!=0) @@ -128,10 +158,12 @@ public: if(atoi(value)) if(mysql_options(connection.handle, MYSQL_OPT_NAMED_PIPE , 0)!=0) services._throw(mysql_error(connection.handle)); + } else if(strcasecmp(key, "multi_statements")==0) { + if(atoi(value)!=0) + connection.multi_statements=true; } else if(strcasecmp(key, "autocommit")==0) { - if(atoi(value)==0) { + if(atoi(value)==0) connection.autocommit=false; - } } else services._throw("unknown connect option" /*key*/); } else @@ -140,14 +172,18 @@ public: } } + // if(connection.cstrClientCharset && cstrBackwardCompAskServerToTranscode) + // services._throw("use 'ClientCharset' option only, " + // "'charset' option is obsolete and should not be used with new 'ClientCharset' option"); + if(!mysql_real_connect(connection.handle, - host, user, pwd, db, port?port:MYSQL_PORT, unix_socket, 0)) + host, user, pwd, db, port?port:MYSQL_PORT, unix_socket, (connection.multi_statements) ? CLIENT_MULTI_STATEMENTS : CLIENT_MULTI_RESULTS)) services._throw(mysql_error(connection.handle)); - if(charset) { + if(cstrBackwardCompAskServerToTranscode) { // set charset - char statement[MAX_STRING]="set CHARACTER SET "; // cp1251_koi8 - strncat(statement, charset, MAX_STRING); + char statement[MAX_STRING]="set CHARACTER SET "; + strncat(statement, cstrBackwardCompAskServerToTranscode, MAX_STRING); exec(connection, statement); } @@ -169,6 +205,7 @@ public: connection.handle=0; } void commit(void *aconnection) { + //_asm int 3; Connection& connection=*static_cast(aconnection); if(!connection.autocommit) @@ -199,14 +236,28 @@ public: mysql_escape_string(result, from, length); return result; } - void query( - void *aconnection, - const char *astatement, unsigned long offset, unsigned long limit, + 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(aconnection); SQL_Driver_services& services=*connection.services; + const char* cstrClientCharset=connection.cstrClientCharset; MYSQL_RES *res=NULL; + if(placeholders_count>0) + services._throw("bind variables not supported (yet)"); + + // transcode from $request:charset to connect-string?client_charset + if(cstrClientCharset) { + size_t transcoded_statement_size; + services.transcode(astatement, strlen(astatement), + astatement, transcoded_statement_size, + services.request_charset(), + cstrClientCharset); + } + const char *statement; if(offset || limit) { size_t statement_size=strlen(astatement); @@ -249,10 +300,20 @@ public: for(int i=0; iname); - char* str=(char*)services.malloc_atomic(length+1); - memcpy(str, field->name, length+1); - CHECK(handlers.add_column(sql_error, str, length)); + size_t length=strlen(field->name); + char* strm=(char*)services.malloc_atomic(length+1); + memcpy(strm, field->name, length+1); + const char* str=strm; + + // transcode to $request:charset from connect-string?client_charset + if(cstrClientCharset) { + services.transcode(str, length, + str, length, + cstrClientCharset, + 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" @@ -268,11 +329,19 @@ public: unsigned long *lengths=mysql_fetch_lengths(res); for(int i=0; i