2 * Copyright (C) 2006, Simon Hyde
3 * http://www.mvpmc.org/
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 #include <sys/types.h>
23 #include <cmyth_local.h>
25 #define CMYTH_ULONG_STRLEN ((sizeof(long)*3)+1)
26 #define CMYTH_LONG_STRLEN (CMYTH_ULONG_STRLEN+1)
29 * Hold in-progress query
31 struct cmyth_mysql_query_s
35 const char * source_pos;
36 int buf_size, buf_used, source_len;
42 * Internal only! Registered as callback to de-allocate actual buffer if
43 * the query is de-allocated
44 * \param p pointer to the query data structure
47 query_destroy(void *p)
49 cmyth_mysql_query_t * query = (cmyth_mysql_query_t *)p;
50 if(query->buf != NULL)
52 ref_release(query->buf);
58 ref_release(query->db);
64 * Allocate a dynamic query string to have parameters added to it
65 * \param db database connection object
66 * \param query_string Query string with ? placemarks for all dynamic
67 * parameters, this is NOT copied and must therefore
68 * remain valid for the life of the query.
71 cmyth_mysql_query_create(cmyth_database_t db, const char * query_string)
73 cmyth_mysql_query_t * out;
74 out = ref_alloc(sizeof(*out));
77 ref_set_destroy(out,query_destroy);
78 out->source = out->source_pos = query_string;
79 out->source_len = strlen(out->source);
80 out->buf_size = out->source_len *2;
82 out->db = ref_hold(db);
83 out->buf = ref_alloc(out->buf_size);
99 cmyth_mysql_query_reset(cmyth_mysql_query_t *query)
102 query->source_pos = query->source;
106 query_buffer_check_len(cmyth_mysql_query_t *query, int len)
108 if(len + query->buf_used >= query->buf_size)
110 /* Increase buffer size by len or out->source_len, whichever
113 if(query->source_len > len)
114 query->buf_size += query->source_len;
116 query->buf_size += len;
117 query->buf = ref_realloc(query->buf,query->buf_size);
118 if(query->buf == NULL)
120 cmyth_mysql_query_reset(query);
128 query_buffer_add(cmyth_mysql_query_t *query, const char *buf,int len)
130 int ret = query_buffer_check_len(query,len);
133 memcpy(query->buf + query->buf_used,buf,len);
134 query->buf_used +=len;
135 query->buf[query->buf_used] = '\0';
140 query_buffer_add_str(cmyth_mysql_query_t *query, const char *str)
142 return query_buffer_add(query,str,strlen(str));
146 query_buffer_add_escape_str(cmyth_mysql_query_t *query, const char *str)
149 int srclen = strlen(str);
151 unsigned long destlen;
152 /*According to the mysql C API refrence, there must be sourcelen*2 +1
153 * characters of space in the destination buffer
155 ret = query_buffer_check_len(query,srclen*2 +1);
158 mysql = cmyth_db_get_connection(query->db);
161 destlen = mysql_real_escape_string(mysql, query->buf + query->buf_used,
163 query->buf_used += destlen;
164 /* MySQL claims it null terminates, but do so anyway just in case we've
165 * done something stupid
167 query->buf[query->buf_used] = '\0';
172 query_begin_next_param(cmyth_mysql_query_t *query)
175 const char * endpos = strchr(query->source_pos,(int)'?');
176 /*No more parameter insertion points left!*/
179 len = endpos - query->source_pos;
180 ret = query_buffer_add(query,query->source_pos,len);
181 query->source_pos = endpos + 1;
186 query_buffer_add_long(cmyth_mysql_query_t * query, long param)
188 char buf[CMYTH_LONG_STRLEN];
189 sprintf(buf,"%ld",param);
190 return query_buffer_add_str(query,buf);
194 query_buffer_add_ulong(cmyth_mysql_query_t * query, long param)
196 char buf[CMYTH_ULONG_STRLEN];
197 sprintf(buf,"%lu",param);
198 return query_buffer_add_str(query,buf);
202 * Add a long integer parameter
203 * \param query the query object
204 * \param param the integer to add
207 cmyth_mysql_query_param_long(cmyth_mysql_query_t * query,long param)
210 ret = query_begin_next_param(query);
213 return query_buffer_add_long(query,param);
217 * Add an unsigned long integer parameter
218 * \param query the query object
219 * \param param the integer to add
222 cmyth_mysql_query_param_ulong(cmyth_mysql_query_t * query,unsigned long param)
225 ret = query_begin_next_param(query);
228 return query_buffer_add_ulong(query,param);
232 * Add an integer parameter
233 * \param query the query object
234 * \param param the integer to add
237 cmyth_mysql_query_param_int(cmyth_mysql_query_t * query,int param)
239 return cmyth_mysql_query_param_long(query,(long)param);
243 * Add an unsigned integer parameter
244 * \param query the query object
245 * \param param the integer to add
248 cmyth_mysql_query_param_uint(cmyth_mysql_query_t * query,int param)
250 return cmyth_mysql_query_param_ulong(query,(unsigned long)param);
254 * Add, and convert a unixtime to mysql date/timestamp
255 * \param query the query object
256 * \param param the time to add
259 cmyth_mysql_query_param_unixtime(cmyth_mysql_query_t * query, time_t param)
262 ret = query_begin_next_param(query);
265 ret = query_buffer_add_str(query,"FROM_UNIXTIME(");
268 ret = query_buffer_add_long(query,(long)param);
271 return query_buffer_add_str(query,")");
276 * Add (including adding quotes), and escape a string parameter.
277 * \param query the query object
278 * \param param the string to add
281 cmyth_mysql_query_param_str(cmyth_mysql_query_t * query, const char *param)
284 ret = query_begin_next_param(query);
288 return query_buffer_add_str(query,"NULL");
289 ret = query_buffer_add_str(query,"'");
292 ret = query_buffer_add_escape_str(query,param);
295 return query_buffer_add_str(query,"'");
299 * Get the completed query string
300 * \return If all fields haven't been filled, or there is some other failure
301 * this will return NULL, otherwise a string is returned. The returned
302 * string must be released by the caller using ref_release().
305 cmyth_mysql_query_string(cmyth_mysql_query_t * query)
307 if(strchr(query->source_pos, (int)'?') != NULL)
309 return NULL;/*Still more parameters to be added*/
311 if(query_buffer_add_str(query,query->source_pos) < 0)
313 /*Point source_pos to the '\0' at the end of the string so this can
314 * be called multiple times
316 query->source_pos = query->source + query->source_len;
317 return ref_hold(query->buf);
322 cmyth_mysql_query_result(cmyth_mysql_query_t * query)
324 MYSQL_RES * retval = NULL;
327 MYSQL *mysql = cmyth_db_get_connection(query->db);
330 query_str = cmyth_mysql_query_string(query);
331 if(query_str == NULL)
333 ret = mysql_query(mysql,query_str);
334 ref_release(query_str);
337 cmyth_dbg(CMYTH_DBG_ERROR, "%s: mysql_query(%s) Failed: %s\n",
338 __FUNCTION__, query_str, mysql_error(mysql));
341 retval = mysql_store_result(mysql);
344 cmyth_dbg(CMYTH_DBG_ERROR, "%s: mysql_use_result Failed: %s\n",
345 __FUNCTION__, query_str, mysql_error(mysql));
351 cmyth_mysql_query(cmyth_mysql_query_t * query)
355 MYSQL *mysql = cmyth_db_get_connection(query->db);
358 query_str = cmyth_mysql_query_string(query);
359 if(query_str == NULL)
361 ret = mysql_query(mysql,query_str);
362 ref_release(query_str);
365 cmyth_dbg(CMYTH_DBG_ERROR, "%s: mysql_query(%s) Failed: %s\n",
366 __FUNCTION__, query_str, mysql_error(mysql));