--- sql/mysql/parser3mysql.C 2010/10/18 21:48:22 1.37 +++ sql/mysql/parser3mysql.C 2012/08/31 08:33:29 1.44 @@ -1,7 +1,7 @@ /** @file Parser MySQL driver. - Copyright(c) 2001-2009 ArtLebedev Group (http://www.artlebedev.com) + Copyright (c) 2001-2012 Art. Lebedev Studio (http://www.artlebedev.com) Author: Alexandr Petrosian (http://paf.design.ru) @@ -10,12 +10,13 @@ 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.37 2010/10/18 21:48:22 moko Exp $"; #include "config_includes.h" #include "pa_sql_driver.h" +volatile const char * IDENT_PARSER3MYSQL_C="$Id: parser3mysql.C,v 1.44 2012/08/31 08:33:29 moko Exp $" IDENT_PA_SQL_DRIVER_H; + #define NO_CLIENT_LONG_LONG #include "mysql.h" #include "ltdl.h" @@ -73,6 +74,46 @@ static void toupper_str(char *out, const *out++=(char)toupper(*in++); } +inline static bool is_column_transcode_required(enum_field_types type) { + switch(type) { + case MYSQL_TYPE_NULL: + + case MYSQL_TYPE_DECIMAL: + case MYSQL_TYPE_NEWDECIMAL: + case MYSQL_TYPE_FLOAT: + case MYSQL_TYPE_DOUBLE: + + case MYSQL_TYPE_TINY: + case MYSQL_TYPE_SHORT: + case MYSQL_TYPE_LONG: + case MYSQL_TYPE_LONGLONG: + case MYSQL_TYPE_INT24: + case MYSQL_TYPE_BIT: + + case MYSQL_TYPE_DATE: + case MYSQL_TYPE_NEWDATE: + case MYSQL_TYPE_TIME: + case MYSQL_TYPE_DATETIME: + case MYSQL_TYPE_YEAR: + case MYSQL_TYPE_TIMESTAMP: + + case MYSQL_TYPE_BLOB: + case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_MEDIUM_BLOB: + case MYSQL_TYPE_LONG_BLOB: + return false; + break; + } + return true; +} + +inline static const char* strdup(SQL_Driver_services& services, char* str, size_t length) { + char *strm=(char*)services.malloc_atomic(length+1); + memcpy(strm, str, length); + strm[length]=0; + return (const char*)strm; +} + struct Connection { SQL_Driver_services* services; @@ -180,6 +221,10 @@ 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, "local_infile")==0){ + if(atoi(value)) + if(mysql_options(connection.handle, MYSQL_OPT_LOCAL_INFILE, 0)!=0) + services._throw(mysql_error(connection.handle)); } else if(strcasecmp(key, "autocommit")==0){ if(atoi(value)==0) connection.autocommit=false; @@ -221,7 +266,7 @@ public: } if(charset){ - char statement[MAX_STRING]="SET CHARACTER SET "; + char statement[MAX_STRING+1]="SET CHARACTER SET "; strncat(statement, charset, MAX_STRING); _exec(connection, statement); } @@ -328,39 +373,42 @@ public: 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, + size_t statement_size=0; + + if(transcode_needed) { + statement_size=strlen(astatement); + // transcode query from $request:charset to ?ClientCharset + services.transcode(astatement, statement_size, + astatement, statement_size, services.request_charset(), connection.client_charset); } const char *statement; - if(offset || limit!=SQL_NO_LIMIT){ - size_t statement_size=strlen(astatement); + if(offset || limit!=SQL_NO_LIMIT) { + if(!statement_size) + statement_size=strlen(astatement); char *statement_limited=(char *)services.malloc_atomic( statement_size+MAX_NUMBER*2+8/* LIMIT #,#*/+1); char *cur=statement_limited; memcpy(cur, astatement, statement_size); cur+=statement_size; cur+=sprintf(cur, " LIMIT "); if(offset) - cur+=snprintf(cur, MAX_NUMBER+1, "%u,", offset); + cur+=snprintf(cur, MAX_NUMBER, "%lu,", offset); if(limit!=SQL_NO_LIMIT) - cur+=snprintf(cur, MAX_NUMBER, "%u", limit); + cur+=snprintf(cur, MAX_NUMBER, "%lu", limit); statement=statement_limited; } else statement=astatement; if(mysql_query(connection.handle, statement)) _throw(connection, mysql_error(connection.handle)); - if(!(res=mysql_store_result(connection.handle)) && mysql_field_count(connection.handle)) + if(!(res=mysql_store_result(connection.handle)) && mysql_field_count(connection.handle)) _throw(connection, mysql_error(connection.handle)); if(!res) // empty result: insert|delete|update|... return; - - int column_count=mysql_num_fields(res); + + size_t column_count=mysql_num_fields(res); if(!column_count) // old client column_count=mysql_field_count(connection.handle); @@ -368,65 +416,76 @@ public: mysql_free_result(res); services._throw("result contains no columns"); } - + bool failed=false; SQL_Error sql_error; -#define CHECK(afailed) \ - if(afailed) { \ - failed=true; \ + +#define CHECK(afailed) \ + if(afailed) { \ + failed=true; \ goto cleanup; \ } - for(int i=0; iname); - char* strm=(char*)services.malloc_atomic(length+1); - memcpy(strm, field->name, length+1); - const char* str=strm; - - // transcode column name from ?ClientCharset to $request:charset - if(transcode_needed){ +#define DO_FETCH_FIELDS(transcode_column_name) { \ + for(size_t i=0; iname_length; \ + const char* str=strdup(services, field->name, length); \ + transcode_column_name \ + CHECK(handlers.add_column(sql_error, str, length)); \ + } else { \ + /* seen broken client, that reported "44" column count for "select 2+2" */ \ + column_count=i; \ + break; \ + } \ + } \ + } + +#define DO_FETCH_ROWS(transcode_cell_value) { \ + while(MYSQL_ROW mysql_row=mysql_fetch_row(res)) { \ + CHECK(handlers.add_row(sql_error)); \ + unsigned long *lengths=mysql_fetch_lengths(res); \ + for(size_t i=0; itype); + // transcode column's name from ?ClientCharset to $request:charset + services.transcode(str, length, + str, length, + connection.client_charset, + services.request_charset()); + ) + CHECK(handlers.before_rows(sql_error)); + DO_FETCH_ROWS( + if(transcode_column[i]) + // transcode cell's value from ?ClientCharset to $request:charset 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; - } - } - - CHECK(handlers.before_rows(sql_error)); - - while(MYSQL_ROW mysql_row=mysql_fetch_row(res)){ - CHECK(handlers.add_row(sql_error)); - unsigned long *lengths=mysql_fetch_lengths(res); - for(int i=0; i