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