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