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