Removed all code that uses OpenGL from Image.
[io/quag.git] / addons / MySQL / source / IoMySQL.c
blob8550fb821489d7edd315bb2440994159583e7005
1 /*#io
2 MySQL ioDoc(
3 docCopyright("Min-hee Hong", 2007)
4 docLicense("MIT License")
5 docObject("MySQL")
6 docDescription("""<a href="http://www.mysql.com/">MySQL</a> is a fast, multi-threaded, multi-user SQL database server. IoMySQL is a MySQL binding for Io, by <a href="http://dahlia.pe.kr/">Min-hee Hong</a>.
8 <pre><code>
9 my := MySQL establish(&quot;localhost&quot;, &quot;user&quot;, &quot;password&quot;, &quot;database&quot;)
11 # Get rows by Map
12 my queryThenMap(&quot;SELECT * FROM rel&quot;) foreach(at(&quot;col&quot;) println)
13 # Get rows by List
14 my query(&quot;SELECT * FROM rel&quot;) foreach(at(0) println)
16 my close
17 </code></pre>
18 """)
19 docCategory("Databases")
22 #include "IoMySQL.h"
23 #include "IoMessage.h"
24 #include "IoState.h"
25 #include "IoNumber.h"
26 #include "IoSeq.h"
27 #include "IoList.h"
28 #include "IoMap.h"
30 #define DATA(self) ((IoMySQLData*) IoObject_dataPointer(self))
32 IoTag* IoMySQL_newTag(void* state) {
33 IoTag* tag = IoTag_newWithName_("MySQL");
34 IoTag_state_(tag, state);
35 IoTag_freeFunc_(tag, (IoTagFreeFunc*) IoMySQL_free);
36 IoTag_cloneFunc_(tag, (IoTagCloneFunc*) IoMySQL_rawClone);
37 return tag;
40 IoObject* IoMySQL_proto(void* state) {
41 IoObject* self = IoObject_new(state);
42 IoObject_tag_(self, IoMySQL_newTag(state));
44 IoObject_setDataPointer_(self, calloc(1, sizeof(IoMySQLData)));
46 IoState_registerProtoWithFunc_(state, self, IoMySQL_proto);
49 IoMethodTable methodTable[] = {
50 {"establish", IoMySQL_establish},
51 {"connect", IoMySQL_connect},
52 {"connected", IoMySQL_connected},
53 {"close", IoMySQL_close},
54 {"query", IoMySQL_query},
55 {"lastInsertRowId", IoMySQL_lastInsertRowId},
56 {NULL, NULL}
59 IoObject_addMethodTable_(self, methodTable);
61 return self;
64 IoObject* IoMySQL_rawClone(IoObject* proto) {
65 IoObject* self = IoObject_rawClonePrimitive(proto);
66 IoObject_setDataPointer_(self, calloc(1, sizeof(IoMySQLData)));
67 return self;
70 IoObject* IoMySQL_new(void* state) {
71 IoObject* proto = IoState_protoWithInitFunction_(state, IoMySQL_proto);
72 return IOCLONE(proto);
75 void IoMySQL_free(IoObject* self) {
76 if(DATA(self)->connected)
77 mysql_close(&DATA(self)->connection);
78 free(IoObject_dataPointer(self));
81 /* ----------------------------------------------------------- */
83 IoObject* IoMySQL_establish(IoObject* self, IoObject* locals, IoMessage* m) {
84 /*#io
85 docSlot("establish",
86 "Establish a connection to a MySQL database.")
88 IoObject* result = IoMySQL_new(IOSTATE);
89 IoMySQL_connect(result, locals, m);
90 return result;
93 IoObject* IoMySQL_connect(IoObject* self, IoObject* locals, IoMessage* m) {
94 IoObject *host = NULL, *user = NULL, *password = NULL, *database = NULL, *port = NULL, *socket = NULL, *ssl = NULL;
96 /*#io
97 docSlot("connect(host, user, password, database, port, unixSocket, useSSL)",
98 "Connect to a MySQL database.")
101 switch(IoMessage_argCount(m)) {
102 case 7: ssl = IoMessage_locals_quickValueArgAt_(m, locals, 6);
103 case 6: socket = IoMessage_locals_quickValueArgAt_(m, locals, 5);
104 case 5: port = IoMessage_locals_quickValueArgAt_(m, locals, 4);
105 case 4: database = IoMessage_locals_quickValueArgAt_(m, locals, 3);
106 case 3: password = IoMessage_locals_quickValueArgAt_(m, locals, 2);
107 case 2: user = IoMessage_locals_quickValueArgAt_(m, locals, 1);
108 case 1: host = IoMessage_locals_quickValueArgAt_(m, locals, 0);
111 if(DATA(self)->connected)
112 mysql_close(&DATA(self)->connection);
114 if(mysql_real_connect(
115 &DATA(self)->connection,
116 host && ISSEQ(host) ? IoSeq_asCString(host) : NULL,
117 user && ISSEQ(user) ? IoSeq_asCString(user) : NULL,
118 password && ISSEQ(password) ? IoSeq_asCString(password) : NULL,
119 database && ISSEQ(database) ? IoSeq_asCString(database) : NULL,
120 port && ISNUMBER(port) ? (unsigned) IoNumber_asInt(port) : 0,
121 socket && ISSEQ(socket) ? IoSeq_asCString(socket) : NULL,
122 ssl && ISFALSE(ssl) ? 0 : CLIENT_SSL
123 )) {
124 DATA(self)->connected = 1;
126 IoObject_setSlot_to_(self, IOSYMBOL("host"), host ? host : IONIL(self));
127 IoObject_setSlot_to_(self, IOSYMBOL("user"), user ? user : IONIL(self));
128 IoObject_setSlot_to_(self, IOSYMBOL("password"), password ? password : IONIL(self));
129 IoObject_setSlot_to_(self, IOSYMBOL("database"), database ? database : IONIL(self));
130 IoObject_setSlot_to_(self, IOSYMBOL("port"), port ? port : IONIL(self));
131 IoObject_setSlot_to_(self, IOSYMBOL("socket"), socket ? socket : IONIL(self));
132 IoObject_setSlot_to_(self, IOSYMBOL("usingSSL"), ssl ? IOBOOL(self, ISTRUE(ssl)) : IOFALSE(self));
134 else
135 IoState_error_(IOSTATE, m, "connection error(%d): %s", mysql_errno(&DATA(self)->connection), mysql_error(&DATA(self)->connection));
137 return self;
140 IoObject* IoMySQL_connected(IoObject* self, IoObject* locals, IoMessage* m) {
141 return IOBOOL(self, DATA(self)->connected);
144 IoObject* IoMySQL_close(IoObject* self, IoObject* locals, IoMessage* m) {
145 /*#io
146 docSlot("close",
147 "Closes a previously opened connection.")
150 if(DATA(self)->connected)
151 mysql_close(&DATA(self)->connection);
153 IoObject_removeSlot_(self, IOSYMBOL("host"));
154 IoObject_removeSlot_(self, IOSYMBOL("user"));
155 IoObject_removeSlot_(self, IOSYMBOL("password"));
156 IoObject_removeSlot_(self, IOSYMBOL("database"));
157 IoObject_removeSlot_(self, IOSYMBOL("port"));
158 IoObject_removeSlot_(self, IOSYMBOL("socket"));
159 IoObject_removeSlot_(self, IOSYMBOL("usingSSL"));
161 return self;
164 IoObject* IoMySQL_query(IoObject* self, IoObject* locals, IoMessage* m) {
165 IoObject* queryString;
166 bool useMap;
168 MYSQL* conn = &DATA(self)->connection;
169 MYSQL_RES* result;
170 MYSQL_ROW row;
171 MYSQL_FIELD* column;
172 char** columnNames;
173 unsigned c, colLength;
174 unsigned long* colLengths;
175 IoObject *list, *rowObject, *tmpObject;
177 if(IoMessage_argCount(m) < 1 || !ISSEQ(queryString = IoMessage_locals_quickValueArgAt_(m, locals, 0)))
178 IoState_error_(IOSTATE, m, "argument 0 to method 'query' must be a Sequence");
180 useMap = IoMessage_argCount(m) > 1 && ISTRUE(IoMessage_locals_quickValueArgAt_(m, locals, 1));
182 if(!DATA(self)->connected)
183 IoState_error_(IOSTATE, m, "not connected yet");
185 if(mysql_real_query(conn, CSTRING(queryString), IOSEQ_LENGTH(queryString)))
186 IoState_error_(IOSTATE, m, "query error(%d): %s", mysql_errno(&DATA(self)->connection), mysql_error(&DATA(self)->connection));
188 if((result = mysql_store_result(conn)) && (colLength = mysql_num_fields(result))) {
189 list = IoList_new(IOSTATE);
191 if(useMap) {
192 columnNames = (char**) malloc(colLength * sizeof(char*));
193 for(c = 0; c < colLength && (column = mysql_fetch_field(result)); ++c)
194 columnNames[c] = column->name;
196 while(row = mysql_fetch_row(result)) {
197 colLengths = mysql_fetch_lengths(result);
198 rowObject = IoMap_new(IOSTATE);
200 for(c = 0; c < colLength; ++c)
201 IoMap_rawAtPut(rowObject, IOSYMBOL(columnNames[c]), IOSEQ((unsigned char *)row[c], (size_t)colLengths[c]));
203 IoList_rawAppend_(list, rowObject);
206 free(columnNames);
208 else {
209 while(row = mysql_fetch_row(result)) {
210 colLengths = mysql_fetch_lengths(result);
211 rowObject = IoList_new(IOSTATE);
213 for(c = 0; c < colLength; ++c)
214 IoList_rawAppend_(rowObject, IOSEQ((unsigned char *)row[c], (size_t)colLengths[c]));
216 IoList_rawAppend_(list, rowObject);
220 mysql_free_result(result);
221 return list;
223 else
224 return IONUMBER(mysql_affected_rows(conn));
227 IoObject* IoMySQL_lastInsertRowId(IoObject* self, IoObject* locals, IoMessage* m) {
228 /*#io
229 docSlot("lastInsertRowId",
230 "Returns the value generated for an AUTO_INCREMENT column by the previous INSERT or UPDATE statement.")
233 if(DATA(self)->connected)
234 return IONUMBER(mysql_insert_id(&DATA(self)->connection));
235 else
236 return IOSTATE->ioNil;