impl/ocaml: fix to_literal for text type
[sqlgg.git] / impl / mysql_traits.hpp
blob17d67107289ae3e61587d5f588b9e6b168859ebf
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 #if defined(SQLGG_DEBUG)
27 #include <stdio.h>
28 #endif
30 struct mysql_traits
32 typedef int Int;
33 typedef std::string Text;
34 typedef Text Any;
36 struct row_t
38 template<class T> T* alloc(size_t const count) { return (T*)calloc(count,sizeof(T)); }
40 row_t(MYSQL_STMT* stmt, size_t count) : count(count), stmt(stmt)
42 bind = alloc<MYSQL_BIND>(count);
43 error = alloc<my_bool>(count);
44 length = alloc<unsigned long>(count);
45 is_null = alloc<my_bool>(count);
48 ~row_t()
50 free(bind);
51 free(error);
52 free(length);
53 free(is_null);
56 const size_t count;
57 MYSQL_STMT* stmt;
59 MYSQL_BIND* bind;
60 unsigned long* length;
61 my_bool* error;
62 my_bool* is_null;
65 typedef row_t& row;
66 typedef MYSQL* connection;
68 static void get_column_Int(row r, int index, Int& data)
70 // nothing
73 static void get_column_Text(row r, int index, Text& data)
75 unsigned long const& length = r.length[index];
76 MYSQL_BIND& bind = r.bind[index];
78 if (length > 0)
80 data.resize(length);
81 bind.buffer = (void*)(data.c_str());
82 bind.buffer_length = length;
83 mysql_stmt_fetch_column(r.stmt, r.bind, index, 0);
86 //data.resize(length);
89 static void bind_column_Int(row r, int index, Int& data)
91 MYSQL_BIND& bind = r.bind[index];
93 data = 0;
94 bind.buffer_type = MYSQL_TYPE_LONG;
95 bind.buffer = (void*)&data;
96 bind.is_null = &r.is_null[index];
97 bind.length = &r.length[index];
98 bind.error = &r.error[index];
101 static void bind_column_Text(row r, int index, Text& data)
103 MYSQL_BIND& bind = r.bind[index];
105 bind.buffer_type = MYSQL_TYPE_STRING;
106 bind.buffer = 0;
107 bind.buffer_length = 0;
108 bind.is_null = &r.is_null[index];
109 bind.length = &r.length[index];
110 bind.error = &r.error[index];
113 static void set_param(row r, const Text& val, int index)
115 MYSQL_BIND& bind = r.bind[index];
117 r.length[index] = val.size();
118 bind.length = &r.length[index];
119 bind.buffer_length = val.size();
120 bind.buffer_type = MYSQL_TYPE_STRING;
121 bind.buffer = (void*)val.c_str();
124 static void set_param(row r, const Int& val, int index)
126 MYSQL_BIND& bind = r.bind[index];
128 bind.buffer_type = MYSQL_TYPE_LONG;
129 bind.buffer = (void*)&val;
132 class mysql_stmt
134 public:
135 mysql_stmt(MYSQL_STMT* stmt) : stmt(stmt)
139 void close()
141 if (stmt) mysql_stmt_close(stmt);
142 stmt = NULL;
145 virtual ~mysql_stmt()
147 close();
151 mysql_stmt& operator=(MYSQL_STMT* v)
153 close();
154 stmt = v;
158 operator MYSQL_STMT*()
160 return stmt;
163 private:
164 MYSQL_STMT* stmt;
167 struct no_params
169 void set_params(row) {}
170 enum { count = 0 };
173 template<class T>
174 struct no_binder
176 void get(row,T) {}
177 void bind(row) {}
178 enum { count = 0 };
182 class statement
184 private:
185 connection db;
186 char const* sql;
187 mysql_stmt stmt;
188 bool ready;
190 public:
191 statement(connection aDb, char const* sql) : db(aDb), sql(sql), stmt(mysql_stmt_init(aDb))
193 ready = false;
196 bool prepare()
198 if (ready)
200 return true;
203 if (!stmt)
205 #if defined(SQLGG_DEBUG)
206 fprintf(stderr, " mysql_stmt_init(), out of memory\n");
207 #endif
208 return false;
211 if (mysql_stmt_prepare(stmt, sql, strlen(sql)))
213 #if defined(SQLGG_DEBUG)
214 fprintf(stderr, " mysql_stmt_prepare(), failed\n");
215 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
216 #endif
217 return false;
220 ready = true;
221 return true;
224 template<class T, class Binder, class Params>
225 bool select(T result, Binder binder, Params params)
227 prepare();
229 if (Params::count != mysql_stmt_param_count(stmt))
231 #if defined(SQLGG_DEBUG)
232 fprintf(stderr, " wrong params count %u != %lu\n",Params::count,mysql_stmt_param_count(stmt));
233 #endif
234 return false;
236 if (Binder::count != mysql_stmt_field_count(stmt))
238 #if defined(SQLGG_DEBUG)
239 fprintf(stderr, " wrong number of columns %u != %u\n",Binder::count,mysql_stmt_field_count(stmt));
240 #endif
241 return false;
244 row_t r_params(stmt,Params::count);
245 params.set_params(r_params);
247 if (mysql_stmt_bind_param(stmt, r_params.bind))
249 #if defined(SQLGG_DEBUG)
250 fprintf(stderr, " mysql_stmt_bind_param() failed\n");
251 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
252 #endif
253 return false;
256 if (mysql_stmt_execute(stmt))
258 #if defined(SQLGG_DEBUG)
259 fprintf(stderr, " mysql_stmt_execute(), failed\n");
260 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
261 #endif
262 return false;
265 row_t r(stmt,Binder::count);
267 if (0 != Binder::count)
269 binder.bind(r);
271 if (mysql_stmt_bind_result(stmt, r.bind))
273 #if defined(SQLGG_DEBUG)
274 fprintf(stderr, " mysql_stmt_bind_result() failed\n");
275 fprintf(stderr, " %s\n", mysql_stmt_error(stmt));
276 #endif
277 return false;
281 while (true)
283 int res = mysql_stmt_fetch(stmt);
284 if (0 != res && MYSQL_DATA_TRUNCATED != res) break;
285 binder.get(r,result);
288 return true;
291 template<class Params>
292 bool execute(Params params)
294 int dummy = 0;
295 return select(dummy,no_binder<int>(),params);
298 }; // statement
300 }; // mysql_traits