SQLiteC++  0.5.0
SQLiteC++ is a smart and easy to use C++ SQLite3 wrapper.
 All Classes Namespaces Files Functions Friends Macros
Statement.cpp
Go to the documentation of this file.
1 /**
2  * @file Statement.cpp
3  * @brief A prepared SQLite Statement is a compiled SQL query ready to be executed, pointing to a row of result.
4  *
5  * Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
6  *
7  * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
8  * or copy at http://opensource.org/licenses/MIT)
9  */
10 #include "Statement.h"
11 
12 #include "Database.h"
13 #include "Column.h"
14 
15 namespace SQLite
16 {
17 
18 // Compile and register the SQL query for the provided SQLite Database Connection
19 Statement::Statement(Database &aDatabase, const char* apQuery) : // throw(SQLite::Exception)
20  mQuery(apQuery),
21  mStmtPtr(aDatabase.mpSQLite, mQuery), // prepare the SQL query, and ref count (needs Database friendship)
22  mColumnCount(0),
23  mbOk(false),
24  mbDone(false)
25 {
26  mColumnCount = sqlite3_column_count(mStmtPtr);
27 }
28 
29 // Finalize and unregister the SQL query from the SQLite Database Connection.
30 Statement::~Statement(void) throw() // nothrow
31 {
32  // the finalization will be done by the destructor of the last shared pointer
33 }
34 
35 // Reset the statement to make it ready for a new execution
36 void Statement::reset(void) // throw(SQLite::Exception)
37 {
38  mbOk = false;
39  mbDone = false;
40  int ret = sqlite3_reset(mStmtPtr);
41  check(ret);
42 }
43 
44 // Bind an int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
45 void Statement::bind(const int aIndex, const int& aValue) // throw(SQLite::Exception)
46 {
47  int ret = sqlite3_bind_int(mStmtPtr, aIndex, aValue);
48  check(ret);
49 }
50 
51 // Bind a 64bits int value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
52 void Statement::bind(const int aIndex, const sqlite3_int64& aValue) // throw(SQLite::Exception)
53 {
54  int ret = sqlite3_bind_int64(mStmtPtr, aIndex, aValue);
55  check(ret);
56 }
57 
58 // Bind a double (64bits float) value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
59 void Statement::bind(const int aIndex, const double& aValue) // throw(SQLite::Exception)
60 {
61  int ret = sqlite3_bind_double(mStmtPtr, aIndex, aValue);
62  check(ret);
63 }
64 
65 // Bind a string value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
66 void Statement::bind(const int aIndex, const std::string& aValue) // throw(SQLite::Exception)
67 {
68  int ret = sqlite3_bind_text(mStmtPtr, aIndex, aValue.c_str(), aValue.size(), SQLITE_TRANSIENT);
69  check(ret);
70 }
71 
72 // Bind a text value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
73 void Statement::bind(const int aIndex, const char* apValue) // throw(SQLite::Exception)
74 {
75  int ret = sqlite3_bind_text(mStmtPtr, aIndex, apValue, -1, SQLITE_TRANSIENT);
76  check(ret);
77 }
78 
79 // Bind a binary blob value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
80 void Statement::bind(const int aIndex, const void* apValue, const int aSize) // throw(SQLite::Exception)
81 {
82  int ret = sqlite3_bind_blob(mStmtPtr, aIndex, apValue, aSize, SQLITE_TRANSIENT);
83  check(ret);
84 }
85 
86 // Bind a NULL value to a parameter "?", "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
87 void Statement::bind(const int aIndex) // throw(SQLite::Exception)
88 {
89  int ret = sqlite3_bind_null(mStmtPtr, aIndex);
90  check(ret);
91 }
92 
93 
94 // Bind an int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
95 void Statement::bind(const char* apName, const int& aValue) // throw(SQLite::Exception)
96 {
97  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
98  int ret = sqlite3_bind_int(mStmtPtr, index, aValue);
99  check(ret);
100 }
101 
102 // Bind a 64bits int value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
103 void Statement::bind(const char* apName, const sqlite3_int64& aValue) // throw(SQLite::Exception)
104 {
105  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
106  int ret = sqlite3_bind_int64(mStmtPtr, index, aValue);
107  check(ret);
108 }
109 
110 // Bind a double (64bits float) value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
111 void Statement::bind(const char* apName, const double& aValue) // throw(SQLite::Exception)
112 {
113  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
114  int ret = sqlite3_bind_double(mStmtPtr, index, aValue);
115  check(ret);
116 }
117 
118 // Bind a string value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
119 void Statement::bind(const char* apName, const std::string& aValue) // throw(SQLite::Exception)
120 {
121  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
122  int ret = sqlite3_bind_text(mStmtPtr, index, aValue.c_str(), aValue.size(), SQLITE_TRANSIENT);
123  check(ret);
124 }
125 
126 // Bind a text value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
127 void Statement::bind(const char* apName, const char* apValue) // throw(SQLite::Exception)
128 {
129  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
130  int ret = sqlite3_bind_text(mStmtPtr, index, apValue, -1, SQLITE_TRANSIENT);
131  check(ret);
132 }
133 
134 // Bind a binary blob value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
135 void Statement::bind(const char* apName, const void* apValue, const int aSize) // throw(SQLite::Exception)
136 {
137  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
138  int ret = sqlite3_bind_blob(mStmtPtr, index, apValue, aSize, SQLITE_TRANSIENT);
139  check(ret);
140 }
141 
142 // Bind a NULL value to a parameter "?NNN", ":VVV", "@VVV" or "$VVV" in the SQL prepared statement
143 void Statement::bind(const char* apName) // throw(SQLite::Exception)
144 {
145  int index = sqlite3_bind_parameter_index(mStmtPtr, apName);
146  int ret = sqlite3_bind_null(mStmtPtr, index);
147  check(ret);
148 }
149 
150 
151 // Execute a step of the query to fetch one row of results
152 bool Statement::executeStep(void) // throw(SQLite::Exception)
153 {
154  if (false == mbDone)
155  {
156  int ret = sqlite3_step(mStmtPtr);
157  if (SQLITE_ROW == ret) // one row is ready : call getColumn(N) to access it
158  {
159  mbOk = true;
160  }
161  else if (SQLITE_DONE == ret) // no (more) row ready : the query has finished executing
162  {
163  mbOk = false;
164  mbDone = true;
165  }
166  else
167  {
168  mbOk = false;
169  mbDone = false;
170  throw SQLite::Exception(sqlite3_errmsg(mStmtPtr));
171  }
172  }
173  else
174  {
175  throw SQLite::Exception("Statement need to be reseted");
176  }
177 
178  return mbOk; // true only if one row is accessible by getColumn(N)
179 }
180 
181 // Execute a one-step query with no expected result
182 int Statement::exec(void) // throw(SQLite::Exception)
183 {
184  if (false == mbDone)
185  {
186  int ret = sqlite3_step(mStmtPtr);
187  if (SQLITE_DONE == ret) // the statement has finished executing successfully
188  {
189  mbOk = false;
190  mbDone = true;
191  }
192  else if (SQLITE_ROW == ret)
193  {
194  mbOk = false;
195  mbDone = false;
196  throw SQLite::Exception("exec() does not expect results");
197  }
198  else
199  {
200  mbOk = false;
201  mbDone = false;
202  throw SQLite::Exception(sqlite3_errmsg(mStmtPtr));
203  }
204  }
205  else
206  {
207  throw SQLite::Exception("Statement need to be reseted");
208  }
209 
210  // Return the number of rows modified by those SQL statements (INSERT, UPDATE or DELETE)
211  return sqlite3_changes(mStmtPtr);
212 }
213 
214 // Return a copy of the column data specified by its index starting at 0
215 // (use the Column copy-constructor)
216 Column Statement::getColumn(const int aIndex) // throw(SQLite::Exception)
217 {
218  if (false == mbOk)
219  {
220  throw SQLite::Exception("No row to get a column from");
221  }
222  else if ((aIndex < 0) || (aIndex >= mColumnCount))
223  {
224  throw SQLite::Exception("Column index out of range");
225  }
226 
227  // Share the Statement Object handle with the new Column created
228  return Column(mStmtPtr, aIndex);
229 }
230 
231 // Test if the column is NULL
232 bool Statement::isColumnNull(const int aIndex) const // throw(SQLite::Exception)
233 {
234  if (false == mbOk)
235  {
236  throw SQLite::Exception("No row to get a column from");
237  }
238  else if ((aIndex < 0) || (aIndex >= mColumnCount))
239  {
240  throw SQLite::Exception("Column index out of range");
241  }
242 
243  return (SQLITE_NULL == sqlite3_column_type(mStmtPtr, aIndex));
244 }
245 
246 // Check if aRet equal SQLITE_OK, else throw a SQLite::Exception with the SQLite error message
247 void Statement::check(const int aRet) const // throw(SQLite::Exception)
248 {
249  if (SQLITE_OK != aRet)
250  {
251  throw SQLite::Exception(sqlite3_errmsg(mStmtPtr));
252  }
253 }
254 
255 
256 ////////////////////////////////////////////////////////////////////////////////
257 // Internal class : shared pointer to the sqlite3_stmt SQLite Statement Object
258 ////////////////////////////////////////////////////////////////////////////////
259 
260 /**
261  * @brief Prepare the statement and initialize its reference counter
262  *
263  * @param[in] apSQLite The sqlite3 database connexion
264  * @param[in] aQuery The SQL query string to prepare
265  */
266 Statement::Ptr::Ptr(sqlite3* apSQLite, std::string& aQuery) :
267  mpSQLite(apSQLite),
268  mpStmt(NULL),
269  mpRefCount(NULL)
270 {
271  int ret = sqlite3_prepare_v2(apSQLite, aQuery.c_str(), aQuery.size(), &mpStmt, NULL);
272  if (SQLITE_OK != ret)
273  {
274  throw SQLite::Exception(sqlite3_errmsg(mpSQLite));
275  }
276  // Initialize the reference counter of the sqlite3_stmt :
277  // used to share the mStmtPtr between Statement and Column objects;
278  // This is needed to enable Column objects to live longer than the Statement objet it refers to.
279  mpRefCount = new unsigned int(1);
280 }
281 
282 /**
283  * @brief Copy constructor increments the ref counter
284  *
285  * @param[in] aPtr Pointer to copy
286  */
288  mpSQLite(aPtr.mpSQLite),
289  mpStmt(aPtr.mpStmt),
290  mpRefCount(aPtr.mpRefCount)
291 {
292  assert(NULL != mpRefCount);
293  assert(0 != *mpRefCount);
294 
295  // Increment the reference counter of the sqlite3_stmt,
296  // asking not to finalize the sqlite3_stmt during the lifetime of the new objet
297  ++(*mpRefCount);
298 }
299 
300 /**
301  * @brief Decrement the ref counter and finalize the sqlite3_stmt when it reaches 0
302  */
303 Statement::Ptr::~Ptr(void) throw() // nothrow
304 {
305  assert(NULL != mpRefCount);
306  assert(0 != *mpRefCount);
307 
308  // Decrement and check the reference counter of the sqlite3_stmt
309  --(*mpRefCount);
310  if (0 == *mpRefCount)
311  {
312  // If count reaches zero, finalize the sqlite3_stmt,
313  // as no Statement not Column objet use it anymore
314  int ret = sqlite3_finalize(mpStmt);
315  // Never throw an exception in a destructor
316  //std::cout << sqlite3_errmsg(mpSQLite) << std::endl;
317  SQLITE_CPP_ASSERT (SQLITE_OK == ret);
318 
319  // and delete the reference counter
320  delete mpRefCount;
321  mpRefCount = NULL;
322  mpStmt = NULL;
323  }
324  // else, the finalization will be done later, by the last object
325 }
326 
327 } // namespace SQLite