actually allow to infer float types
[sqlgg.git] / impl / mysql_traits.hpp
blobc4a19066ba04ef0fac16579e2191d5f763ee2daf
1 /*
2 Mysql C++ traits for sqlgg
3 by ygrek
4 2014-06-08
6 This is free and unencumbered software released into the public domain.
8 Anyone is free to copy, modify, publish, use, compile, sell, or
9 distribute this software, either in source code form or as a compiled
10 binary, for any purpose, commercial or non-commercial, and by any
11 means.
13 For more information, please refer to <http://unlicense.org/>
16 #include <mysql/mysql.h>
17 #define SQLGG_STR(x) x
19 #include <assert.h>
20 #include <string.h>
21 #include <stdlib.h>
23 #include <string>
24 #include <vector>
26 struct mysql_traits
28 typedef int Int;
29 typedef std::string Text;
30 typedef Text Any;
32 struct row_t
34 template<class T> T* alloc(size_t const count) { return (T*)calloc(count,sizeof(T)); }
36 row_t(MYSQL_STMT* stmt, size_t count) : count(count), stmt(stmt)
38 bind = alloc<MYSQL_BIND>(count);
39 error = alloc<my_bool>(count);
40 length = alloc<unsigned long>(count);
41 is_null = alloc<my_bool>(count);
44 ~row_t()
46 free(bind);
47 free(error);
48 free(length);
49 free(is_null);
52 const size_t count;
53 MYSQL_STMT* stmt;
55 MYSQL_BIND* bind;
56 unsigned long* length;
57 my_bool* error;
58 my_bool* is_null;
61 typedef row_t& row;
62 typedef MYSQL* connection;
64 static void get_column_Int(row r, int index, Int& data)
66 // nothing
69 static void get_column_Text(row r, int index, Text& data)
71 unsigned long const& length = r.length[index];
72 MYSQL_BIND& bind = r.bind[index];
74 if (length > 0)
76 data.resize(length);
77 bind.buffer = (void*)(data.c_str());
78 bind.buffer_length = length;
79 mysql_stmt_fetch_column(r.stmt, r.bind, index, 0);
82 //data.resize(length);
85 static void bind_column_Int(row r, int index, Int& data)
87 MYSQL_BIND& bind = r.bind[index];
89 data = 0;
90 bind.buffer_type = MYSQL_TYPE_LONG;
91 bind.buffer = (void*)&data;
92 bind.is_null = &r.is_null[index];
93 bind.length = &r.length[index];
94 bind.error = &r.error[index];
97 static void bind_column_Text(row r, int index, Text& data)
99 MYSQL_BIND& bind = r.bind[index];
101 bind.buffer_type = MYSQL_TYPE_STRING;
102 bind.buffer = 0;
103 bind.buffer_length = 0;
104 bind.is_null = &r.is_null[index];
105 bind.length = &r.length[index];
106 bind.error = &r.error[index];
109 static void set_param(row r, const Text& val, int index)
111 MYSQL_BIND& bind = r.bind[index];
113 r.length[index] = val.size();
114 bind.length = &r.length[index];
115 bind.buffer_length = val.size();
116 bind.buffer_type = MYSQL_TYPE_STRING;
117 bind.buffer = (void*)val.c_str();
120 static void set_param(row r, const Int& val, int index)
122 MYSQL_BIND& bind = r.bind[index];
124 bind.buffer_type = MYSQL_TYPE_LONG;
125 bind.buffer = (void*)&val;
128 class mysql_stmt
130 public:
131 mysql_stmt(MYSQL_STMT* stmt) : stmt(stmt)
135 void close()
137 if (stmt) mysql_stmt_close(stmt);
138 stmt = NULL;
141 virtual ~mysql_stmt()
143 close();
147 mysql_stmt& operator=(MYSQL_STMT* v)
149 close();
150 stmt = v;
154 operator MYSQL_STMT*()
156 return stmt;
159 private:
160 MYSQL_STMT* stmt;
163 struct no_params
165 void set_params(row) {}
166 enum { count = 0 };
169 template<class T>
170 struct no_binder
172 void get(row,T) {}
173 void bind(row) {}
174 enum { count = 0 };
178 class statement
180 private:
181 connection db;
182 char const* sql;
183 mysql_stmt stmt;
184 bool ready;
186 public:
187 statement(connection aDb, char const* sql) : db(aDb), sql(sql), stmt(mysql_stmt_init(aDb))
189 ready = false;
192 bool prepare()
194 if (ready)
196 return true;
199 if (!stmt)
201 #if defined(SQLGG_DEBUG)
202 fprintf(stderr, " mysql_stmt_init(), out of memory\n");
203 #endif
204 return false;
207 if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
209 #if defined(SQLGG_DEBUG)
210 fprintf(stderr, " mysql_stmt_prepare(), failed\n");
211 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
212 #endif
213 return false;
216 ready = true;
217 return true;
220 template<class T, class Binder, class Params>
221 bool select(T result, Binder binder, Params params)
223 prepare();
225 if (Params::count != mysql_stmt_param_count(stmt))
227 #if defined(SQLGG_DEBUG)
228 fprintf(stderr, " wrong params count %u != %lu\n",Params::count,mysql_stmt_param_count(stmt));
229 #endif
230 return false;
232 if (Binder::count != mysql_stmt_field_count(stmt))
234 #if defined(SQLGG_DEBUG)
235 fprintf(stderr, " wrong number of columns %u != %u\n",Binder::count,mysql_stmt_field_count(stmt));
236 #endif
237 return false;
240 row_t r_params(stmt,Params::count);
241 params.set_params(r_params);
243 if (mysql_stmt_bind_param(stmt, r_params.bind))
245 #if defined(SQLGG_DEBUG)
246 fprintf(stderr, " mysql_stmt_bind_param() failed\n");
247 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
248 #endif
249 return false;
252 if (mysql_stmt_execute(stmt))
254 #if defined(SQLGG_DEBUG)
255 fprintf(stderr, " mysql_stmt_execute(), failed\n");
256 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
257 #endif
258 return false;
261 row_t r(stmt,Binder::count);
263 if (0 != Binder::count)
265 binder.bind(r);
267 if (mysql_stmt_bind_result(stmt, r.bind))
269 #if defined(SQLGG_DEBUG)
270 fprintf(stderr, " mysql_stmt_bind_result() failed\n");
271 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
272 #endif
273 return false;
277 while (true)
279 int res = mysql_stmt_fetch(stmt);
280 if (0 != res && MYSQL_DATA_TRUNCATED != res) break;
281 binder.get(r,result);
284 return true;
287 template<class Params>
288 bool execute(Params params)
290 int dummy;
291 return select(dummy,no_binder<int>(),params);
294 }; // statement
296 }; // mysql_traits