1 : /* Any copyright is dedicated to the Public Domain.
2 : http://creativecommons.org/publicdomain/zero/1.0/ */
3 :
4 : #include "storage_test_harness.h"
5 :
6 : #include "nsIEventTarget.h"
7 : #include "mozStorageConnection.h"
8 :
9 : #include "sqlite3.h"
10 :
11 : using namespace mozilla;
12 : using namespace mozilla::storage;
13 :
14 : ////////////////////////////////////////////////////////////////////////////////
15 : //// Helpers
16 :
17 : /**
18 : * Commit hook to detect transactions.
19 : *
20 : * @param aArg
21 : * An integer pointer that will be incremented for each commit.
22 : */
23 8 : int commit_hook(void *aArg)
24 : {
25 8 : int *arg = static_cast<int *>(aArg);
26 8 : (*arg)++;
27 8 : return 0;
28 : }
29 :
30 : /**
31 : * Executes the passed-in statements and checks if a transaction is created.
32 : * When done statements are finalized and database connection is closed.
33 : *
34 : * @param aDB
35 : * The database connection.
36 : * @param aStmts
37 : * Vector of statements.
38 : * @param aStmtsLen
39 : * Number of statements.
40 : * @param aTransactionExpected
41 : * Whether a transaction is expected or not.
42 : */
43 : void
44 14 : check_transaction(mozIStorageConnection *aDB,
45 : mozIStorageBaseStatement **aStmts,
46 : PRUint32 aStmtsLen,
47 : bool aTransactionExpected)
48 : {
49 : // -- install a transaction commit hook.
50 14 : int commit = 0;
51 14 : ::sqlite3_commit_hook(*static_cast<Connection *>(aDB), commit_hook, &commit);
52 :
53 28 : nsRefPtr<AsyncStatementSpinner> asyncSpin(new AsyncStatementSpinner());
54 28 : nsCOMPtr<mozIStoragePendingStatement> asyncPend;
55 14 : do_check_success(aDB->ExecuteAsync(aStmts, aStmtsLen, asyncSpin,
56 : getter_AddRefs(asyncPend)));
57 14 : do_check_true(asyncPend);
58 :
59 : // -- complete the execution
60 14 : asyncSpin->SpinUntilCompleted();
61 :
62 : // -- uninstall the transaction commit hook.
63 14 : ::sqlite3_commit_hook(*static_cast<Connection *>(aDB), NULL, NULL);
64 :
65 : // -- check transaction
66 14 : do_check_eq(aTransactionExpected, !!commit);
67 :
68 : // -- check that only one transaction was created.
69 14 : if (aTransactionExpected) {
70 8 : do_check_eq(1, commit);
71 : }
72 :
73 : // -- cleanup
74 34 : for (PRUint32 i = 0; i < aStmtsLen; ++i) {
75 20 : aStmts[i]->Finalize();
76 : }
77 14 : blocking_async_close(aDB);
78 14 : }
79 :
80 : ////////////////////////////////////////////////////////////////////////////////
81 : //// Tests
82 :
83 : /**
84 : * Test that executing multiple readonly AsyncStatements doesn't create a
85 : * transaction.
86 : */
87 : void
88 1 : test_MultipleAsyncReadStatements()
89 : {
90 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
91 :
92 : // -- create statements and execute them
93 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt1;
94 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
95 : "SELECT * FROM sqlite_master"
96 2 : ), getter_AddRefs(stmt1));
97 :
98 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt2;
99 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
100 : "SELECT * FROM sqlite_master"
101 2 : ), getter_AddRefs(stmt2));
102 :
103 : mozIStorageBaseStatement *stmts[] = {
104 : stmt1,
105 : stmt2,
106 1 : };
107 :
108 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
109 1 : }
110 :
111 : /**
112 : * Test that executing multiple readonly Statements doesn't create a
113 : * transaction.
114 : */
115 : void
116 1 : test_MultipleReadStatements()
117 : {
118 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
119 :
120 : // -- create statements and execute them
121 2 : nsCOMPtr<mozIStorageStatement> stmt1;
122 2 : db->CreateStatement(NS_LITERAL_CSTRING(
123 : "SELECT * FROM sqlite_master"
124 2 : ), getter_AddRefs(stmt1));
125 :
126 2 : nsCOMPtr<mozIStorageStatement> stmt2;
127 2 : db->CreateStatement(NS_LITERAL_CSTRING(
128 : "SELECT * FROM sqlite_master"
129 2 : ), getter_AddRefs(stmt2));
130 :
131 : mozIStorageBaseStatement *stmts[] = {
132 : stmt1,
133 : stmt2,
134 1 : };
135 :
136 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
137 1 : }
138 :
139 : /**
140 : * Test that executing multiple AsyncStatements causing writes creates a
141 : * transaction.
142 : */
143 : void
144 1 : test_MultipleAsyncReadWriteStatements()
145 : {
146 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
147 :
148 : // -- create statements and execute them
149 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt1;
150 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
151 : "SELECT * FROM sqlite_master"
152 2 : ), getter_AddRefs(stmt1));
153 :
154 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt2;
155 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
156 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
157 2 : ), getter_AddRefs(stmt2));
158 :
159 : mozIStorageBaseStatement *stmts[] = {
160 : stmt1,
161 : stmt2,
162 1 : };
163 :
164 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
165 1 : }
166 :
167 : /**
168 : * Test that executing multiple Statements causing writes creates a transaction.
169 : */
170 : void
171 1 : test_MultipleReadWriteStatements()
172 : {
173 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
174 :
175 : // -- create statements and execute them
176 2 : nsCOMPtr<mozIStorageStatement> stmt1;
177 2 : db->CreateStatement(NS_LITERAL_CSTRING(
178 : "SELECT * FROM sqlite_master"
179 2 : ), getter_AddRefs(stmt1));
180 :
181 2 : nsCOMPtr<mozIStorageStatement> stmt2;
182 2 : db->CreateStatement(NS_LITERAL_CSTRING(
183 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
184 2 : ), getter_AddRefs(stmt2));
185 :
186 : mozIStorageBaseStatement *stmts[] = {
187 : stmt1,
188 : stmt2,
189 1 : };
190 :
191 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
192 1 : }
193 :
194 : /**
195 : * Test that executing multiple AsyncStatements causing writes creates a
196 : * single transaction.
197 : */
198 : void
199 1 : test_MultipleAsyncWriteStatements()
200 : {
201 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
202 :
203 : // -- create statements and execute them
204 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt1;
205 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
206 : "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
207 2 : ), getter_AddRefs(stmt1));
208 :
209 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt2;
210 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
211 : "CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
212 2 : ), getter_AddRefs(stmt2));
213 :
214 : mozIStorageBaseStatement *stmts[] = {
215 : stmt1,
216 : stmt2,
217 1 : };
218 :
219 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
220 1 : }
221 :
222 : /**
223 : * Test that executing multiple Statements causing writes creates a
224 : * single transaction.
225 : */
226 : void
227 1 : test_MultipleWriteStatements()
228 : {
229 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
230 :
231 : // -- create statements and execute them
232 2 : nsCOMPtr<mozIStorageStatement> stmt1;
233 2 : db->CreateStatement(NS_LITERAL_CSTRING(
234 : "CREATE TABLE test1 (id INTEGER PRIMARY KEY)"
235 2 : ), getter_AddRefs(stmt1));
236 :
237 2 : nsCOMPtr<mozIStorageStatement> stmt2;
238 2 : db->CreateStatement(NS_LITERAL_CSTRING(
239 : "CREATE TABLE test2 (id INTEGER PRIMARY KEY)"
240 2 : ), getter_AddRefs(stmt2));
241 :
242 : mozIStorageBaseStatement *stmts[] = {
243 : stmt1,
244 : stmt2,
245 1 : };
246 :
247 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
248 1 : }
249 :
250 : /**
251 : * Test that executing a single read-only AsyncStatement doesn't create a
252 : * transaction.
253 : */
254 : void
255 1 : test_SingleAsyncReadStatement()
256 : {
257 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
258 :
259 : // -- create statements and execute them
260 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt;
261 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
262 : "SELECT * FROM sqlite_master"
263 2 : ), getter_AddRefs(stmt));
264 :
265 : mozIStorageBaseStatement *stmts[] = {
266 : stmt,
267 1 : };
268 :
269 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
270 1 : }
271 :
272 : /**
273 : * Test that executing a single read-only Statement doesn't create a
274 : * transaction.
275 : */
276 : void
277 1 : test_SingleReadStatement()
278 : {
279 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
280 :
281 : // -- create statements and execute them
282 2 : nsCOMPtr<mozIStorageStatement> stmt;
283 2 : db->CreateStatement(NS_LITERAL_CSTRING(
284 : "SELECT * FROM sqlite_master"
285 2 : ), getter_AddRefs(stmt));
286 :
287 : mozIStorageBaseStatement *stmts[] = {
288 : stmt,
289 1 : };
290 :
291 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
292 1 : }
293 :
294 : /**
295 : * Test that executing a single AsyncStatement causing writes creates a
296 : * transaction.
297 : */
298 : void
299 1 : test_SingleAsyncWriteStatement()
300 : {
301 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
302 :
303 : // -- create statements and execute them
304 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt;
305 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
306 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
307 2 : ), getter_AddRefs(stmt));
308 :
309 : mozIStorageBaseStatement *stmts[] = {
310 : stmt,
311 1 : };
312 :
313 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
314 1 : }
315 :
316 : /**
317 : * Test that executing a single Statement causing writes creates a transaction.
318 : */
319 : void
320 1 : test_SingleWriteStatement()
321 : {
322 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
323 :
324 : // -- create statements and execute them
325 2 : nsCOMPtr<mozIStorageStatement> stmt;
326 2 : db->CreateStatement(NS_LITERAL_CSTRING(
327 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
328 2 : ), getter_AddRefs(stmt));
329 :
330 : mozIStorageBaseStatement *stmts[] = {
331 : stmt,
332 1 : };
333 :
334 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
335 1 : }
336 :
337 : /**
338 : * Test that executing a single read-only AsyncStatement with multiple params
339 : * doesn't create a transaction.
340 : */
341 : void
342 1 : test_MultipleParamsAsyncReadStatement()
343 : {
344 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
345 :
346 : // -- create statements and execute them
347 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt;
348 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
349 : "SELECT :param FROM sqlite_master"
350 2 : ), getter_AddRefs(stmt));
351 :
352 : // -- bind multiple BindingParams
353 2 : nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
354 1 : stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
355 3 : for (PRInt32 i = 0; i < 2; i++) {
356 4 : nsCOMPtr<mozIStorageBindingParams> params;
357 2 : paramsArray->NewBindingParams(getter_AddRefs(params));
358 2 : params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
359 2 : paramsArray->AddParams(params);
360 : }
361 1 : stmt->BindParameters(paramsArray);
362 1 : paramsArray = nsnull;
363 :
364 : mozIStorageBaseStatement *stmts[] = {
365 : stmt,
366 1 : };
367 :
368 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
369 1 : }
370 :
371 : /**
372 : * Test that executing a single read-only Statement with multiple params
373 : * doesn't create a transaction.
374 : */
375 : void
376 1 : test_MultipleParamsReadStatement()
377 : {
378 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
379 :
380 : // -- create statements and execute them
381 2 : nsCOMPtr<mozIStorageStatement> stmt;
382 2 : db->CreateStatement(NS_LITERAL_CSTRING(
383 : "SELECT :param FROM sqlite_master"
384 2 : ), getter_AddRefs(stmt));
385 :
386 : // -- bind multiple BindingParams
387 2 : nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
388 1 : stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
389 3 : for (PRInt32 i = 0; i < 2; i++) {
390 4 : nsCOMPtr<mozIStorageBindingParams> params;
391 2 : paramsArray->NewBindingParams(getter_AddRefs(params));
392 2 : params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
393 2 : paramsArray->AddParams(params);
394 : }
395 1 : stmt->BindParameters(paramsArray);
396 1 : paramsArray = nsnull;
397 :
398 : mozIStorageBaseStatement *stmts[] = {
399 : stmt,
400 1 : };
401 :
402 1 : check_transaction(db, stmts, ArrayLength(stmts), false);
403 1 : }
404 :
405 : /**
406 : * Test that executing a single write AsyncStatement with multiple params
407 : * creates a transaction.
408 : */
409 : void
410 1 : test_MultipleParamsAsyncWriteStatement()
411 : {
412 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
413 :
414 : // -- create a table for writes
415 2 : nsCOMPtr<mozIStorageStatement> tableStmt;
416 2 : db->CreateStatement(NS_LITERAL_CSTRING(
417 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
418 2 : ), getter_AddRefs(tableStmt));
419 1 : tableStmt->Execute();
420 1 : tableStmt->Finalize();
421 :
422 : // -- create statements and execute them
423 2 : nsCOMPtr<mozIStorageAsyncStatement> stmt;
424 2 : db->CreateAsyncStatement(NS_LITERAL_CSTRING(
425 : "DELETE FROM test WHERE id = :param"
426 2 : ), getter_AddRefs(stmt));
427 :
428 : // -- bind multiple BindingParams
429 2 : nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
430 1 : stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
431 3 : for (PRInt32 i = 0; i < 2; i++) {
432 4 : nsCOMPtr<mozIStorageBindingParams> params;
433 2 : paramsArray->NewBindingParams(getter_AddRefs(params));
434 2 : params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
435 2 : paramsArray->AddParams(params);
436 : }
437 1 : stmt->BindParameters(paramsArray);
438 1 : paramsArray = nsnull;
439 :
440 : mozIStorageBaseStatement *stmts[] = {
441 : stmt,
442 1 : };
443 :
444 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
445 1 : }
446 :
447 : /**
448 : * Test that executing a single write Statement with multiple params
449 : * creates a transaction.
450 : */
451 : void
452 1 : test_MultipleParamsWriteStatement()
453 : {
454 2 : nsCOMPtr<mozIStorageConnection> db(getMemoryDatabase());
455 :
456 : // -- create a table for writes
457 2 : nsCOMPtr<mozIStorageStatement> tableStmt;
458 2 : db->CreateStatement(NS_LITERAL_CSTRING(
459 : "CREATE TABLE test (id INTEGER PRIMARY KEY)"
460 2 : ), getter_AddRefs(tableStmt));
461 1 : tableStmt->Execute();
462 1 : tableStmt->Finalize();
463 :
464 : // -- create statements and execute them
465 2 : nsCOMPtr<mozIStorageStatement> stmt;
466 2 : db->CreateStatement(NS_LITERAL_CSTRING(
467 : "DELETE FROM test WHERE id = :param"
468 2 : ), getter_AddRefs(stmt));
469 :
470 : // -- bind multiple BindingParams
471 2 : nsCOMPtr<mozIStorageBindingParamsArray> paramsArray;
472 1 : stmt->NewBindingParamsArray(getter_AddRefs(paramsArray));
473 3 : for (PRInt32 i = 0; i < 2; i++) {
474 4 : nsCOMPtr<mozIStorageBindingParams> params;
475 2 : paramsArray->NewBindingParams(getter_AddRefs(params));
476 2 : params->BindInt32ByName(NS_LITERAL_CSTRING("param"), 1);
477 2 : paramsArray->AddParams(params);
478 : }
479 1 : stmt->BindParameters(paramsArray);
480 1 : paramsArray = nsnull;
481 :
482 : mozIStorageBaseStatement *stmts[] = {
483 : stmt,
484 1 : };
485 :
486 1 : check_transaction(db, stmts, ArrayLength(stmts), true);
487 1 : }
488 :
489 : void (*gTests[])(void) = {
490 : test_MultipleAsyncReadStatements,
491 : test_MultipleReadStatements,
492 : test_MultipleAsyncReadWriteStatements,
493 : test_MultipleReadWriteStatements,
494 : test_MultipleAsyncWriteStatements,
495 : test_MultipleWriteStatements,
496 : test_SingleAsyncReadStatement,
497 : test_SingleReadStatement,
498 : test_SingleAsyncWriteStatement,
499 : test_SingleWriteStatement,
500 : test_MultipleParamsAsyncReadStatement,
501 : test_MultipleParamsReadStatement,
502 : test_MultipleParamsAsyncWriteStatement,
503 : test_MultipleParamsWriteStatement,
504 : };
505 :
506 : const char *file = __FILE__;
507 : #define TEST_NAME "async statement execution transaction"
508 : #define TEST_FILE file
509 : #include "storage_test_harness_tail.h"
|