--- parser3/src/sql/mysql/Attic/parser3mysql.C 2001/04/04 12:45:47 1.4 +++ parser3/src/sql/mysql/Attic/parser3mysql.C 2001/04/07 14:23:35 1.12 @@ -1,20 +1,28 @@ /** @file Parser: MySQL driver. - Copyright (c) 2001 ArtLebedev Group (http://www.artlebedev.com) + Copyright(c) 2001 ArtLebedev Group(http://www.artlebedev.com) - Author: Alexander Petrosyan (http://design.ru/paf) + Author: Alexander Petrosyan (http://design.ru/paf) - $Id: parser3mysql.C,v 1.4 2001/04/04 12:45:47 paf Exp $ + $Id: parser3mysql.C,v 1.12 2001/04/07 14:23:35 paf Exp $ */ #include +#include +#include #include "pa_sql_driver.h" #include "mysql.h" -#include "pa_common.h" -char *lsplit(char *string, char delim) { +#define MAX_STRING 0x400 +#define MAX_NUMBER 20 + +#if _MSC_VER +# define snprintf _snprintf +#endif + +static char *lsplit(char *string, char delim) { if(string) { char *v=strchr(string, delim); if(v) { @@ -25,14 +33,13 @@ char *lsplit(char *string, char delim) { return 0; } -char *lsplit(char **string_ref, char delim) { - char *result=*string_ref; - char *next=lsplit(*string_ref, delim); - *string_ref=next; - return result; -} - -/// MySQL server driver +/** + MySQL server driver + + @todo figure out about memory for errors: + static=add multithread locks; + dynamic=who should free it up? +*/ class MySQL_Driver : public SQL_Driver { public: @@ -40,9 +47,14 @@ public: } /// get api version - int api_version() { return SQL_API_VERSION; } + int api_version() { return SQL_DRIVER_API_VERSION; } /// connect - const char *connect(char *url, void **info) { + void connect( + char *url, /**< @b user:pass@host[:port]/database/charset + 3.23.22b + Currently the only option for character_set_name is cp1251_koi8 */ + void **connection ///< output: MYSQL * + ) { char *user=url; char *host=lsplit(user, '@'); char *db=lsplit(host, '/'); @@ -50,26 +62,111 @@ public: char *error_pos=0; char *port_cstr=lsplit(host, ':'); int port=port_cstr?strtol(port_cstr, &error_pos, 0):0; + char *charset=lsplit(db, '/'); MYSQL *mysql=mysql_init(NULL); if(!mysql_real_connect(mysql, host, user, pwd, db, port?port:MYSQL_PORT, NULL, 0)) - return "mysql connect failed"; + services->_throw(mysql_error(mysql)); + + if(charset) { + // set charset + char statement[MAX_STRING]="set CHARACTER SET "; // cp1251_koi8 + strncat(statement, charset, MAX_STRING); + + 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 **)info=mysql; - return 0; + *(MYSQL **)connection=mysql; } - const char *disconnect(void *info) { - mysql_close((MYSQL *)info); - return 0; + void disconnect(void *connection) { + mysql_close((MYSQL *)connection); } - const char *commit(void *info) { - return 0;//"mysql commit failed"; + void commit(void *connection) {} + void rollback(void *connection) {} + + bool ping(void *connection) { + return mysql_ping((MYSQL *)connection)==0; + } + + unsigned int quote(void *connection, + char *to, const char *from, unsigned int length) { + /* + 3.23.22b + 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, + and you need room for the terminating null byte.) + + it's already UNTAINT_TIMES_BIGGER + */ + return mysql_escape_string(to, from, length); } - const char *rollback(void *info) { - return 0;//"mysql rollback failed"; + void query(void *connection, + const char *astatement, unsigned long offset, unsigned long limit, + unsigned int *column_count, Cell **columns, + unsigned long *row_count, Cell ***rows) { + + MYSQL *mysql=(MYSQL *)connection; + MYSQL_RES *res=NULL; + + const char *statement; + if(offset || limit) { + size_t statement_size=strlen(astatement); + char *statement_limited=(char *)services->malloc( + 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, "%lu,", offset); + if(limit) + cur+=snprintf(cur, MAX_NUMBER, "%lu", limit); + statement=statement_limited; + } else + statement=astatement; + + if(mysql_query(mysql, statement)) + services->_throw(mysql_error(mysql)); + if(!(res=mysql_store_result(mysql)) && mysql_field_count(mysql)) + services->_throw(mysql_error(mysql)); + if(!res) { + // empty result + *row_count=0; + *column_count=0; + return; + } + + *column_count=mysql_num_fields(res); + *columns=(Cell *)services->malloc(sizeof(Cell)*(*column_count)); + + *row_count=(unsigned long)mysql_num_rows(res); + *rows=(Cell **)services->malloc(sizeof(Cell *)*(*row_count)); + + for(unsigned int i=0; i<(*column_count); i++){ + MYSQL_FIELD *field=mysql_fetch_field(res); + size_t size=strlen(field->name); + (*columns)[i].size=size; + (*columns)[i].ptr=services->malloc(size); + memcpy((*columns)[i].ptr, field->name, size); + } + + for(unsigned long r=0; r<(*row_count); r++) + if(MYSQL_ROW mysql_row=mysql_fetch_row(res)) { // never false.. + unsigned long *lengths=mysql_fetch_lengths(res); + Cell *row=(Cell *)malloc(sizeof(Cell)*(*column_count)); + (*rows)[r]=row; + for(unsigned int i=0; i<(*column_count); i++){ + size_t size=(size_t)lengths[i]; + row[i].size=size; + row[i].ptr=services->malloc(size); + memcpy(row[i].ptr, mysql_row[i], size); + } + } + + mysql_free_result(res); } - ; }; extern "C" SQL_Driver *create() {