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