Serenity Operating System
1/*
2 * Copyright (c) 2021, Jan de Visser <jan@de-visser.net>
3 * Copyright (c) 2021, Mahmoud Mandour <ma.mandourr@gmail.com>
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#include <unistd.h>
9
10#include <AK/QuickSort.h>
11#include <AK/ScopeGuard.h>
12#include <LibSQL/AST/Parser.h>
13#include <LibSQL/Database.h>
14#include <LibSQL/Result.h>
15#include <LibSQL/ResultSet.h>
16#include <LibSQL/Row.h>
17#include <LibSQL/Value.h>
18#include <LibTest/TestCase.h>
19
20namespace {
21
22constexpr char const* db_name = "/tmp/test.db";
23
24SQL::ResultOr<SQL::ResultSet> try_execute(NonnullRefPtr<SQL::Database> database, DeprecatedString const& sql, Vector<SQL::Value> placeholder_values = {})
25{
26 auto parser = SQL::AST::Parser(SQL::AST::Lexer(sql));
27 auto statement = parser.next_statement();
28 EXPECT(!parser.has_errors());
29 if (parser.has_errors())
30 outln("{}", parser.errors()[0].to_deprecated_string());
31 return statement->execute(move(database), placeholder_values);
32}
33
34SQL::ResultSet execute(NonnullRefPtr<SQL::Database> database, DeprecatedString const& sql, Vector<SQL::Value> placeholder_values = {})
35{
36 auto result = try_execute(move(database), sql, move(placeholder_values));
37 if (result.is_error()) {
38 outln("{}", result.release_error().error_string());
39 VERIFY_NOT_REACHED();
40 }
41 return result.release_value();
42}
43
44template<typename... Args>
45Vector<SQL::Value> placeholders(Args&&... args)
46{
47 return { SQL::Value(forward<Args>(args))... };
48}
49
50void create_schema(NonnullRefPtr<SQL::Database> database)
51{
52 auto result = execute(database, "CREATE SCHEMA TestSchema;");
53 EXPECT_EQ(result.command(), SQL::SQLCommand::Create);
54}
55
56void create_table(NonnullRefPtr<SQL::Database> database)
57{
58 create_schema(database);
59 auto result = execute(database, "CREATE TABLE TestSchema.TestTable ( TextColumn text, IntColumn integer );");
60 EXPECT_EQ(result.command(), SQL::SQLCommand::Create);
61}
62
63void create_two_tables(NonnullRefPtr<SQL::Database> database)
64{
65 create_schema(database);
66 auto result = execute(database, "CREATE TABLE TestSchema.TestTable1 ( TextColumn1 text, IntColumn integer );");
67 EXPECT_EQ(result.command(), SQL::SQLCommand::Create);
68 result = execute(database, "CREATE TABLE TestSchema.TestTable2 ( TextColumn2 text, IntColumn integer );");
69 EXPECT_EQ(result.command(), SQL::SQLCommand::Create);
70}
71
72TEST_CASE(create_schema)
73{
74 ScopeGuard guard([]() { unlink(db_name); });
75 auto database = SQL::Database::construct(db_name);
76 EXPECT(!database->open().is_error());
77 create_schema(database);
78 auto schema_or_error = database->get_schema("TESTSCHEMA");
79 EXPECT(!schema_or_error.is_error());
80}
81
82TEST_CASE(create_table)
83{
84 ScopeGuard guard([]() { unlink(db_name); });
85 auto database = SQL::Database::construct(db_name);
86 EXPECT(!database->open().is_error());
87 create_table(database);
88 auto table_or_error = database->get_table("TESTSCHEMA", "TESTTABLE");
89 EXPECT(!table_or_error.is_error());
90}
91
92TEST_CASE(insert_into_table)
93{
94 ScopeGuard guard([]() { unlink(db_name); });
95 auto database = SQL::Database::construct(db_name);
96 EXPECT(!database->open().is_error());
97 create_table(database);
98 auto result = execute(database, "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test', 42 );");
99 EXPECT(result.size() == 1);
100
101 auto table = MUST(database->get_table("TESTSCHEMA", "TESTTABLE"));
102
103 int count = 0;
104 auto rows_or_error = database->select_all(*table);
105 EXPECT(!rows_or_error.is_error());
106 for (auto& row : rows_or_error.value()) {
107 EXPECT_EQ(row["TEXTCOLUMN"].to_deprecated_string(), "Test");
108 EXPECT_EQ(row["INTCOLUMN"].to_int<i32>(), 42);
109 count++;
110 }
111 EXPECT_EQ(count, 1);
112}
113
114TEST_CASE(insert_into_table_wrong_data_types)
115{
116 ScopeGuard guard([]() { unlink(db_name); });
117 auto database = SQL::Database::construct(db_name);
118 EXPECT(!database->open().is_error());
119 create_table(database);
120 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES (43, 'Test_2');");
121 EXPECT(result.is_error());
122 EXPECT(result.release_error().error() == SQL::SQLErrorCode::InvalidValueType);
123}
124
125TEST_CASE(insert_into_table_multiple_tuples_wrong_data_types)
126{
127 ScopeGuard guard([]() { unlink(db_name); });
128 auto database = SQL::Database::construct(db_name);
129 EXPECT(!database->open().is_error());
130 create_table(database);
131 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ('Test_1', 42), (43, 'Test_2');");
132 EXPECT(result.is_error());
133 EXPECT(result.release_error().error() == SQL::SQLErrorCode::InvalidValueType);
134}
135
136TEST_CASE(insert_wrong_number_of_values)
137{
138 ScopeGuard guard([]() { unlink(db_name); });
139 auto database = SQL::Database::construct(db_name);
140 EXPECT(!database->open().is_error());
141 create_table(database);
142 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES ( 42 );");
143 EXPECT(result.is_error());
144 EXPECT(result.release_error().error() == SQL::SQLErrorCode::InvalidNumberOfValues);
145}
146
147TEST_CASE(insert_identifier_as_value)
148{
149 ScopeGuard guard([]() { unlink(db_name); });
150 auto database = SQL::Database::construct(db_name);
151 EXPECT(!database->open().is_error());
152 create_table(database);
153 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES ( identifier, 42 );");
154 EXPECT(result.is_error());
155 EXPECT(result.release_error().error() == SQL::SQLErrorCode::SyntaxError);
156}
157
158TEST_CASE(insert_quoted_identifier_as_value)
159{
160 ScopeGuard guard([]() { unlink(db_name); });
161 auto database = SQL::Database::construct(db_name);
162 EXPECT(!database->open().is_error());
163 create_table(database);
164 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES ( \"QuotedIdentifier\", 42 );");
165 EXPECT(result.is_error());
166 EXPECT(result.release_error().error() == SQL::SQLErrorCode::SyntaxError);
167}
168
169TEST_CASE(insert_without_column_names)
170{
171 ScopeGuard guard([]() { unlink(db_name); });
172 auto database = SQL::Database::construct(db_name);
173 EXPECT(!database->open().is_error());
174 create_table(database);
175 auto result = execute(database, "INSERT INTO TestSchema.TestTable VALUES ('Test_1', 42), ('Test_2', 43);");
176 EXPECT(result.size() == 2);
177
178 auto table = MUST(database->get_table("TESTSCHEMA", "TESTTABLE"));
179 auto rows_or_error = database->select_all(*table);
180 EXPECT(!rows_or_error.is_error());
181 EXPECT_EQ(rows_or_error.value().size(), 2u);
182}
183
184TEST_CASE(insert_with_placeholders)
185{
186 ScopeGuard guard([]() { unlink(db_name); });
187
188 auto database = SQL::Database::construct(db_name);
189 EXPECT(!database->open().is_error());
190 create_table(database);
191
192 {
193 auto result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?);");
194 EXPECT(result.is_error());
195 EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::InvalidNumberOfPlaceholderValues);
196
197 result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?);", placeholders("Test_1"sv));
198 EXPECT(result.is_error());
199 EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::InvalidNumberOfPlaceholderValues);
200
201 result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?);", placeholders(42, 42));
202 EXPECT(result.is_error());
203 EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::InvalidValueType);
204
205 result = try_execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?);", placeholders("Test_1"sv, "Test_2"sv));
206 EXPECT(result.is_error());
207 EXPECT_EQ(result.error().error(), SQL::SQLErrorCode::InvalidValueType);
208 }
209 {
210 auto result = execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?);", placeholders("Test_1"sv, 42));
211 EXPECT_EQ(result.size(), 1u);
212
213 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn;");
214 EXPECT_EQ(result.size(), 1u);
215
216 EXPECT_EQ(result[0].row[0], "Test_1"sv);
217 EXPECT_EQ(result[0].row[1], 42);
218 }
219 {
220 auto result = execute(database, "INSERT INTO TestSchema.TestTable VALUES (?, ?), (?, ?);", placeholders("Test_2"sv, 43, "Test_3"sv, 44));
221 EXPECT_EQ(result.size(), 2u);
222
223 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn;");
224 EXPECT_EQ(result.size(), 3u);
225
226 EXPECT_EQ(result[0].row[0], "Test_1"sv);
227 EXPECT_EQ(result[0].row[1], 42);
228
229 EXPECT_EQ(result[1].row[0], "Test_2"sv);
230 EXPECT_EQ(result[1].row[1], 43);
231
232 EXPECT_EQ(result[2].row[0], "Test_3"sv);
233 EXPECT_EQ(result[2].row[1], 44);
234 }
235}
236
237TEST_CASE(select_from_empty_table)
238{
239 ScopeGuard guard([]() { unlink(db_name); });
240 auto database = SQL::Database::construct(db_name);
241 EXPECT(!database->open().is_error());
242 create_table(database);
243 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
244 EXPECT(result.is_empty());
245}
246
247TEST_CASE(select_from_table)
248{
249 ScopeGuard guard([]() { unlink(db_name); });
250 auto database = SQL::Database::construct(db_name);
251 EXPECT(!database->open().is_error());
252 create_table(database);
253 auto result = execute(database,
254 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
255 "( 'Test_1', 42 ), "
256 "( 'Test_2', 43 ), "
257 "( 'Test_3', 44 ), "
258 "( 'Test_4', 45 ), "
259 "( 'Test_5', 46 );");
260 EXPECT(result.size() == 5);
261 result = execute(database, "SELECT * FROM TestSchema.TestTable;");
262 EXPECT_EQ(result.size(), 5u);
263}
264
265TEST_CASE(select_with_column_names)
266{
267 ScopeGuard guard([]() { unlink(db_name); });
268 auto database = SQL::Database::construct(db_name);
269 EXPECT(!database->open().is_error());
270 create_table(database);
271 auto result = execute(database,
272 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
273 "( 'Test_1', 42 ), "
274 "( 'Test_2', 43 ), "
275 "( 'Test_3', 44 ), "
276 "( 'Test_4', 45 ), "
277 "( 'Test_5', 46 );");
278 EXPECT(result.size() == 5);
279 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable;");
280 EXPECT_EQ(result.size(), 5u);
281 EXPECT_EQ(result[0].row.size(), 1u);
282}
283
284TEST_CASE(select_with_nonexisting_column_name)
285{
286 ScopeGuard guard([]() { unlink(db_name); });
287 auto database = SQL::Database::construct(db_name);
288 EXPECT(!database->open().is_error());
289 create_table(database);
290 auto result = execute(database,
291 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
292 "( 'Test_1', 42 ), "
293 "( 'Test_2', 43 ), "
294 "( 'Test_3', 44 ), "
295 "( 'Test_4', 45 ), "
296 "( 'Test_5', 46 );");
297 EXPECT(result.size() == 5);
298
299 auto insert_result = try_execute(database, "SELECT Bogus FROM TestSchema.TestTable;");
300 EXPECT(insert_result.is_error());
301 EXPECT(insert_result.release_error().error() == SQL::SQLErrorCode::ColumnDoesNotExist);
302}
303
304TEST_CASE(select_with_where)
305{
306 ScopeGuard guard([]() { unlink(db_name); });
307 auto database = SQL::Database::construct(db_name);
308 EXPECT(!database->open().is_error());
309 create_table(database);
310 auto result = execute(database,
311 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
312 "( 'Test_1', 42 ), "
313 "( 'Test_2', 43 ), "
314 "( 'Test_3', 44 ), "
315 "( 'Test_4', 45 ), "
316 "( 'Test_5', 46 );");
317 EXPECT(result.size() == 5);
318 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable WHERE IntColumn > 44;");
319 EXPECT_EQ(result.size(), 2u);
320 for (auto& row : result) {
321 EXPECT(row.row[1].to_int<i32>().value() > 44);
322 }
323}
324
325TEST_CASE(select_cross_join)
326{
327 ScopeGuard guard([]() { unlink(db_name); });
328 auto database = SQL::Database::construct(db_name);
329 EXPECT(!database->open().is_error());
330 create_two_tables(database);
331 auto result = execute(database,
332 "INSERT INTO TestSchema.TestTable1 ( TextColumn1, IntColumn ) VALUES "
333 "( 'Test_1', 42 ), "
334 "( 'Test_2', 43 ), "
335 "( 'Test_3', 44 ), "
336 "( 'Test_4', 45 ), "
337 "( 'Test_5', 46 );");
338 EXPECT(result.size() == 5);
339 result = execute(database,
340 "INSERT INTO TestSchema.TestTable2 ( TextColumn2, IntColumn ) VALUES "
341 "( 'Test_10', 40 ), "
342 "( 'Test_11', 41 ), "
343 "( 'Test_12', 42 ), "
344 "( 'Test_13', 47 ), "
345 "( 'Test_14', 48 );");
346 EXPECT(result.size() == 5);
347 result = execute(database, "SELECT * FROM TestSchema.TestTable1, TestSchema.TestTable2;");
348 EXPECT_EQ(result.size(), 25u);
349 for (auto& row : result) {
350 EXPECT(row.row.size() == 4);
351 EXPECT(row.row[1].to_int<i32>().value() >= 42);
352 EXPECT(row.row[1].to_int<i32>().value() <= 46);
353 EXPECT(row.row[3].to_int<i32>().value() >= 40);
354 EXPECT(row.row[3].to_int<i32>().value() <= 48);
355 }
356}
357
358TEST_CASE(select_inner_join)
359{
360 ScopeGuard guard([]() { unlink(db_name); });
361 auto database = SQL::Database::construct(db_name);
362 EXPECT(!database->open().is_error());
363 create_two_tables(database);
364 auto result = execute(database,
365 "INSERT INTO TestSchema.TestTable1 ( TextColumn1, IntColumn ) VALUES "
366 "( 'Test_1', 42 ), "
367 "( 'Test_2', 43 ), "
368 "( 'Test_3', 44 ), "
369 "( 'Test_4', 45 ), "
370 "( 'Test_5', 46 );");
371 EXPECT(result.size() == 5);
372 result = execute(database,
373 "INSERT INTO TestSchema.TestTable2 ( TextColumn2, IntColumn ) VALUES "
374 "( 'Test_10', 40 ), "
375 "( 'Test_11', 41 ), "
376 "( 'Test_12', 42 ), "
377 "( 'Test_13', 47 ), "
378 "( 'Test_14', 48 );");
379 EXPECT(result.size() == 5);
380 result = execute(database,
381 "SELECT TestTable1.IntColumn, TextColumn1, TextColumn2 "
382 "FROM TestSchema.TestTable1, TestSchema.TestTable2 "
383 "WHERE TestTable1.IntColumn = TestTable2.IntColumn;");
384 EXPECT_EQ(result.size(), 1u);
385 EXPECT_EQ(result[0].row.size(), 3u);
386 EXPECT_EQ(result[0].row[0].to_int<i32>(), 42);
387 EXPECT_EQ(result[0].row[1].to_deprecated_string(), "Test_1");
388 EXPECT_EQ(result[0].row[2].to_deprecated_string(), "Test_12");
389}
390
391TEST_CASE(select_with_like)
392{
393 ScopeGuard guard([]() { unlink(db_name); });
394 auto database = SQL::Database::construct(db_name);
395 EXPECT(!database->open().is_error());
396 create_table(database);
397 auto result = execute(database,
398 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
399 "( 'Test+1', 42 ), "
400 "( 'Test+2', 43 ), "
401 "( 'Test+3', 44 ), "
402 "( 'Test+4', 45 ), "
403 "( 'Test+5', 46 ), "
404 "( 'Another+Test_6', 47 );");
405 EXPECT(result.size() == 6);
406
407 // Simple match
408 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE 'Test+1';");
409 EXPECT_EQ(result.size(), 1u);
410
411 // Use % to match most rows
412 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE 'T%';");
413 EXPECT_EQ(result.size(), 5u);
414
415 // Same as above but invert the match
416 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn NOT LIKE 'T%';");
417 EXPECT_EQ(result.size(), 1u);
418
419 // Use _ and % to match all rows
420 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE '%e_t%';");
421 EXPECT_EQ(result.size(), 6u);
422
423 // Use escape to match a single row. The escape character happens to be a
424 // Regex metacharacter, let's make sure we don't get confused by that.
425 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE '%Test^_%' ESCAPE '^';");
426 EXPECT_EQ(result.size(), 1u);
427
428 // Same as above but escape the escape character happens to be a SQL
429 // metacharacter - we want to make sure it's treated as an escape.
430 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE '%Test__%' ESCAPE '_';");
431 EXPECT_EQ(result.size(), 1u);
432
433 // (Unnecessarily) escaping a character that happens to be a Regex
434 // metacharacter should have no effect.
435 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE 'Test:+_' ESCAPE ':';");
436 EXPECT_EQ(result.size(), 5u);
437
438 // Make sure we error out if the ESCAPE is empty
439 auto select_result = try_execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE '%' ESCAPE '';");
440 EXPECT(select_result.is_error());
441 EXPECT(select_result.release_error().error() == SQL::SQLErrorCode::SyntaxError);
442
443 // Make sure we error out if the ESCAPE has more than a single character
444 select_result = try_execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn LIKE '%' ESCAPE 'whf';");
445 EXPECT(select_result.is_error());
446 EXPECT(select_result.release_error().error() == SQL::SQLErrorCode::SyntaxError);
447}
448
449TEST_CASE(select_with_order)
450{
451 ScopeGuard guard([]() { unlink(db_name); });
452 auto database = SQL::Database::construct(db_name);
453 EXPECT(!database->open().is_error());
454 create_table(database);
455 auto result = execute(database,
456 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
457 "( 'Test_5', 44 ), "
458 "( 'Test_2', 42 ), "
459 "( 'Test_1', 47 ), "
460 "( 'Test_3', 40 ), "
461 "( 'Test_4', 41 );");
462 EXPECT(result.size() == 5);
463
464 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
465 EXPECT_EQ(result.size(), 5u);
466 EXPECT_EQ(result[0].row[1].to_int<i32>(), 40);
467 EXPECT_EQ(result[1].row[1].to_int<i32>(), 41);
468 EXPECT_EQ(result[2].row[1].to_int<i32>(), 42);
469 EXPECT_EQ(result[3].row[1].to_int<i32>(), 44);
470 EXPECT_EQ(result[4].row[1].to_int<i32>(), 47);
471
472 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn;");
473 EXPECT_EQ(result.size(), 5u);
474 EXPECT_EQ(result[0].row[0].to_deprecated_string(), "Test_1");
475 EXPECT_EQ(result[1].row[0].to_deprecated_string(), "Test_2");
476 EXPECT_EQ(result[2].row[0].to_deprecated_string(), "Test_3");
477 EXPECT_EQ(result[3].row[0].to_deprecated_string(), "Test_4");
478 EXPECT_EQ(result[4].row[0].to_deprecated_string(), "Test_5");
479}
480
481TEST_CASE(select_with_regexp)
482{
483 ScopeGuard guard([]() { unlink(db_name); });
484 auto database = SQL::Database::construct(db_name);
485 EXPECT(!database->open().is_error());
486 create_table(database);
487 auto result = execute(database,
488 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
489 "( 'Test+1', 42 ), "
490 "( 'Pröv+2', 43 ), "
491 "( 'Test(3)', 44 ), "
492 "( 'Test[4]', 45 ), "
493 "( 'Test+5', 46 ), "
494 "( 'Another-Test_6', 47 );");
495 EXPECT(result.size() == 6);
496
497 // Simple match
498 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn REGEXP 'Test\\+1';");
499 EXPECT_EQ(result.size(), 1u);
500
501 // Match all
502 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn REGEXP '.*';");
503 EXPECT_EQ(result.size(), 6u);
504
505 // Match with wildcards
506 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn REGEXP '^Test.+';");
507 EXPECT_EQ(result.size(), 4u);
508
509 // Match with case insensitive basic Latin and case sensitive Swedish ö
510 // FIXME: If LibRegex is changed to support case insensitive matches of Unicode characters
511 // This test should be updated and changed to match 'PRÖV'.
512 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn REGEXP 'PRöV.*';");
513 EXPECT_EQ(result.size(), 1u);
514}
515
516TEST_CASE(handle_regexp_errors)
517{
518 ScopeGuard guard([]() { unlink(db_name); });
519 auto database = SQL::Database::construct(db_name);
520 EXPECT(!database->open().is_error());
521 create_table(database);
522 auto result = execute(database,
523 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
524 "( 'Test', 0 );");
525 EXPECT(result.size() == 1);
526
527 // Malformed regex, unmatched square bracket
528 auto select_result = try_execute(database, "SELECT TextColumn FROM TestSchema.TestTable WHERE TextColumn REGEXP 'Test\\+[0-9.*';");
529 EXPECT(select_result.is_error());
530}
531
532TEST_CASE(select_with_order_two_columns)
533{
534 ScopeGuard guard([]() { unlink(db_name); });
535 auto database = SQL::Database::construct(db_name);
536 EXPECT(!database->open().is_error());
537 create_table(database);
538 auto result = execute(database,
539 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
540 "( 'Test_5', 44 ), "
541 "( 'Test_2', 42 ), "
542 "( 'Test_1', 47 ), "
543 "( 'Test_2', 40 ), "
544 "( 'Test_4', 41 );");
545 EXPECT(result.size() == 5);
546
547 result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY TextColumn, IntColumn;");
548 EXPECT_EQ(result.size(), 5u);
549 EXPECT_EQ(result[0].row[0].to_deprecated_string(), "Test_1");
550 EXPECT_EQ(result[0].row[1].to_int<i32>(), 47);
551 EXPECT_EQ(result[1].row[0].to_deprecated_string(), "Test_2");
552 EXPECT_EQ(result[1].row[1].to_int<i32>(), 40);
553 EXPECT_EQ(result[2].row[0].to_deprecated_string(), "Test_2");
554 EXPECT_EQ(result[2].row[1].to_int<i32>(), 42);
555 EXPECT_EQ(result[3].row[0].to_deprecated_string(), "Test_4");
556 EXPECT_EQ(result[3].row[1].to_int<i32>(), 41);
557 EXPECT_EQ(result[4].row[0].to_deprecated_string(), "Test_5");
558 EXPECT_EQ(result[4].row[1].to_int<i32>(), 44);
559}
560
561TEST_CASE(select_with_order_by_column_not_in_result)
562{
563 ScopeGuard guard([]() { unlink(db_name); });
564 auto database = SQL::Database::construct(db_name);
565 EXPECT(!database->open().is_error());
566 create_table(database);
567 auto result = execute(database,
568 "INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES "
569 "( 'Test_5', 44 ), "
570 "( 'Test_2', 42 ), "
571 "( 'Test_1', 47 ), "
572 "( 'Test_3', 40 ), "
573 "( 'Test_4', 41 );");
574 EXPECT(result.size() == 5);
575
576 result = execute(database, "SELECT TextColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
577 EXPECT_EQ(result.size(), 5u);
578 EXPECT_EQ(result[0].row[0].to_deprecated_string(), "Test_3");
579 EXPECT_EQ(result[1].row[0].to_deprecated_string(), "Test_4");
580 EXPECT_EQ(result[2].row[0].to_deprecated_string(), "Test_2");
581 EXPECT_EQ(result[3].row[0].to_deprecated_string(), "Test_5");
582 EXPECT_EQ(result[4].row[0].to_deprecated_string(), "Test_1");
583}
584
585TEST_CASE(select_with_limit)
586{
587 ScopeGuard guard([]() { unlink(db_name); });
588 auto database = SQL::Database::construct(db_name);
589 EXPECT(!database->open().is_error());
590 create_table(database);
591 for (auto count = 0; count < 100; count++) {
592 auto result = execute(database,
593 DeprecatedString::formatted("INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test_{}', {} );", count, count));
594 EXPECT(result.size() == 1);
595 }
596 auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable LIMIT 10;");
597 auto rows = result;
598 EXPECT_EQ(rows.size(), 10u);
599}
600
601TEST_CASE(select_with_limit_and_offset)
602{
603 ScopeGuard guard([]() { unlink(db_name); });
604 auto database = SQL::Database::construct(db_name);
605 EXPECT(!database->open().is_error());
606 create_table(database);
607 for (auto count = 0; count < 100; count++) {
608 auto result = execute(database,
609 DeprecatedString::formatted("INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test_{}', {} );", count, count));
610 EXPECT(result.size() == 1);
611 }
612 auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable LIMIT 10 OFFSET 10;");
613 EXPECT_EQ(result.size(), 10u);
614}
615
616TEST_CASE(select_with_order_limit_and_offset)
617{
618 ScopeGuard guard([]() { unlink(db_name); });
619 auto database = SQL::Database::construct(db_name);
620 EXPECT(!database->open().is_error());
621 create_table(database);
622 for (auto count = 0; count < 100; count++) {
623 auto result = execute(database,
624 DeprecatedString::formatted("INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test_{}', {} );", count, count));
625 EXPECT(result.size() == 1);
626 }
627 auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable ORDER BY IntColumn LIMIT 10 OFFSET 10;");
628 EXPECT_EQ(result.size(), 10u);
629 EXPECT_EQ(result[0].row[1].to_int<i32>(), 10);
630 EXPECT_EQ(result[1].row[1].to_int<i32>(), 11);
631 EXPECT_EQ(result[2].row[1].to_int<i32>(), 12);
632 EXPECT_EQ(result[3].row[1].to_int<i32>(), 13);
633 EXPECT_EQ(result[4].row[1].to_int<i32>(), 14);
634 EXPECT_EQ(result[5].row[1].to_int<i32>(), 15);
635 EXPECT_EQ(result[6].row[1].to_int<i32>(), 16);
636 EXPECT_EQ(result[7].row[1].to_int<i32>(), 17);
637 EXPECT_EQ(result[8].row[1].to_int<i32>(), 18);
638 EXPECT_EQ(result[9].row[1].to_int<i32>(), 19);
639}
640
641TEST_CASE(select_with_limit_out_of_bounds)
642{
643 ScopeGuard guard([]() { unlink(db_name); });
644 auto database = SQL::Database::construct(db_name);
645 EXPECT(!database->open().is_error());
646 create_table(database);
647 for (auto count = 0; count < 100; count++) {
648 auto result = execute(database,
649 DeprecatedString::formatted("INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test_{}', {} );", count, count));
650 EXPECT(result.size() == 1);
651 }
652 auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable LIMIT 500;");
653 EXPECT_EQ(result.size(), 100u);
654}
655
656TEST_CASE(select_with_offset_out_of_bounds)
657{
658 ScopeGuard guard([]() { unlink(db_name); });
659 auto database = SQL::Database::construct(db_name);
660 EXPECT(!database->open().is_error());
661 create_table(database);
662 for (auto count = 0; count < 100; count++) {
663 auto result = execute(database,
664 DeprecatedString::formatted("INSERT INTO TestSchema.TestTable ( TextColumn, IntColumn ) VALUES ( 'Test_{}', {} );", count, count));
665 EXPECT(result.size() == 1);
666 }
667 auto result = execute(database, "SELECT TextColumn, IntColumn FROM TestSchema.TestTable LIMIT 10 OFFSET 200;");
668 EXPECT_EQ(result.size(), 0u);
669}
670
671TEST_CASE(describe_table)
672{
673 ScopeGuard guard([]() { unlink(db_name); });
674 auto database = SQL::Database::construct(db_name);
675 EXPECT(!database->open().is_error());
676 create_table(database);
677 auto result = execute(database, "DESCRIBE TABLE TestSchema.TestTable;");
678 EXPECT_EQ(result.size(), 2u);
679
680 EXPECT_EQ(result[0].row[0].to_deprecated_string(), "TEXTCOLUMN");
681 EXPECT_EQ(result[0].row[1].to_deprecated_string(), "text");
682
683 EXPECT_EQ(result[1].row[0].to_deprecated_string(), "INTCOLUMN");
684 EXPECT_EQ(result[1].row[1].to_deprecated_string(), "int");
685}
686
687TEST_CASE(binary_operator_execution)
688{
689 ScopeGuard guard([]() { unlink(db_name); });
690 auto database = SQL::Database::construct(db_name);
691 EXPECT(!database->open().is_error());
692 create_table(database);
693
694 for (auto count = 0; count < 10; ++count) {
695 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
696 EXPECT_EQ(result.size(), 1u);
697 }
698
699 auto compare_result = [](SQL::ResultSet const& result, Vector<int> const& expected) {
700 EXPECT_EQ(result.command(), SQL::SQLCommand::Select);
701 EXPECT_EQ(result.size(), expected.size());
702
703 Vector<int> result_values;
704 result_values.ensure_capacity(result.size());
705
706 for (size_t i = 0; i < result.size(); ++i) {
707 auto const& result_row = result.at(i).row;
708 EXPECT_EQ(result_row.size(), 1u);
709
710 auto result_column = result_row[0].to_int<i32>();
711 result_values.append(result_column.value());
712 }
713
714 quick_sort(result_values);
715 EXPECT_EQ(result_values, expected);
716 };
717
718 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn + 1) < 5);");
719 compare_result(result, { 0, 1, 2, 3 });
720
721 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn + 1) <= 5);");
722 compare_result(result, { 0, 1, 2, 3, 4 });
723
724 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn - 1) > 4);");
725 compare_result(result, { 6, 7, 8, 9 });
726
727 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn - 1) >= 4);");
728 compare_result(result, { 5, 6, 7, 8, 9 });
729
730 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn * 2) < 10);");
731 compare_result(result, { 0, 1, 2, 3, 4 });
732
733 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn * 2) <= 10);");
734 compare_result(result, { 0, 1, 2, 3, 4, 5 });
735
736 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn / 3) > 2);");
737 compare_result(result, { 7, 8, 9 });
738
739 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn / 3) >= 2);");
740 compare_result(result, { 6, 7, 8, 9 });
741
742 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn % 2) = 0);");
743 compare_result(result, { 0, 2, 4, 6, 8 });
744
745 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn % 2) = 1);");
746 compare_result(result, { 1, 3, 5, 7, 9 });
747
748 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((1 << IntColumn) <= 32);");
749 compare_result(result, { 0, 1, 2, 3, 4, 5 });
750
751 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((1024 >> IntColumn) >= 32);");
752 compare_result(result, { 0, 1, 2, 3, 4, 5 });
753
754 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn | 1) != IntColumn);");
755 compare_result(result, { 0, 2, 4, 6, 8 });
756
757 result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable WHERE ((IntColumn & 1) = 1);");
758 compare_result(result, { 1, 3, 5, 7, 9 });
759}
760
761TEST_CASE(binary_operator_failure)
762{
763 ScopeGuard guard([]() { unlink(db_name); });
764 auto database = SQL::Database::construct(db_name);
765 EXPECT(!database->open().is_error());
766 create_table(database);
767
768 for (auto count = 0; count < 10; ++count) {
769 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
770 EXPECT_EQ(result.size(), 1u);
771 }
772
773 auto expect_failure = [](auto result, auto op) {
774 EXPECT(result.is_error());
775
776 auto error = result.release_error();
777 EXPECT_EQ(error.error(), SQL::SQLErrorCode::NumericOperatorTypeMismatch);
778
779 auto message = DeprecatedString::formatted("NumericOperatorTypeMismatch: Cannot apply '{}' operator to non-numeric operands", op);
780 EXPECT_EQ(error.error_string(), message);
781 };
782
783 auto result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn + TextColumn) < 5);");
784 expect_failure(move(result), '+');
785
786 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn - TextColumn) < 5);");
787 expect_failure(move(result), '-');
788
789 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn * TextColumn) < 5);");
790 expect_failure(move(result), '*');
791
792 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn / TextColumn) < 5);");
793 expect_failure(move(result), '/');
794
795 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn % TextColumn) < 5);");
796 expect_failure(move(result), '%');
797
798 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn << TextColumn) < 5);");
799 expect_failure(move(result), "<<"sv);
800
801 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn >> TextColumn) < 5);");
802 expect_failure(move(result), ">>"sv);
803
804 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn | TextColumn) < 5);");
805 expect_failure(move(result), '|');
806
807 result = try_execute(database, "SELECT * FROM TestSchema.TestTable WHERE ((IntColumn & TextColumn) < 5);");
808 expect_failure(move(result), '&');
809}
810
811TEST_CASE(describe_large_table_after_persist)
812{
813 ScopeGuard guard([]() { unlink(db_name); });
814 {
815 auto database = SQL::Database::construct(db_name);
816 EXPECT(!database->open().is_error());
817
818 auto result = execute(database, "CREATE TABLE Cookies ( name TEXT, value TEXT, same_site INTEGER, creation_time INTEGER, last_access_time INTEGER, expiry_time INTEGER, domain TEXT, path TEXT, secure INTEGER, http_only INTEGER, host_only INTEGER, persistent INTEGER );");
819 EXPECT_EQ(result.command(), SQL::SQLCommand::Create);
820 }
821 {
822 auto database = SQL::Database::construct(db_name);
823 EXPECT(!database->open().is_error());
824
825 auto result = execute(database, "DESCRIBE TABLE Cookies;");
826 EXPECT_EQ(result.size(), 12u);
827 }
828}
829
830TEST_CASE(delete_single_row)
831{
832 ScopeGuard guard([]() { unlink(db_name); });
833 {
834 auto database = SQL::Database::construct(db_name);
835 EXPECT(!database->open().is_error());
836
837 create_table(database);
838 for (auto count = 0; count < 10; ++count) {
839 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
840 EXPECT_EQ(result.size(), 1u);
841 }
842
843 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
844 EXPECT_EQ(result.size(), 10u);
845 }
846 {
847 auto database = SQL::Database::construct(db_name);
848 EXPECT(!database->open().is_error());
849
850 execute(database, "DELETE FROM TestSchema.TestTable WHERE (IntColumn = 4);");
851
852 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
853 EXPECT_EQ(result.size(), 9u);
854
855 for (auto i = 0u; i < 4; ++i)
856 EXPECT_EQ(result[i].row[0], i);
857 for (auto i = 5u; i < 9; ++i)
858 EXPECT_EQ(result[i].row[0], i + 1);
859 }
860 {
861 auto database = SQL::Database::construct(db_name);
862 EXPECT(!database->open().is_error());
863
864 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
865 EXPECT_EQ(result.size(), 9u);
866
867 for (auto i = 0u; i < 4; ++i)
868 EXPECT_EQ(result[i].row[0], i);
869 for (auto i = 5u; i < 9; ++i)
870 EXPECT_EQ(result[i].row[0], i + 1);
871 }
872}
873
874TEST_CASE(delete_multiple_rows)
875{
876 ScopeGuard guard([]() { unlink(db_name); });
877 {
878 auto database = SQL::Database::construct(db_name);
879 EXPECT(!database->open().is_error());
880
881 create_table(database);
882 for (auto count = 0; count < 10; ++count) {
883 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
884 EXPECT_EQ(result.size(), 1u);
885 }
886
887 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
888 EXPECT_EQ(result.size(), 10u);
889 }
890 {
891 auto database = SQL::Database::construct(db_name);
892 EXPECT(!database->open().is_error());
893
894 execute(database, "DELETE FROM TestSchema.TestTable WHERE (IntColumn >= 4);");
895
896 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
897 EXPECT_EQ(result.size(), 4u);
898
899 for (auto i = 0u; i < result.size(); ++i)
900 EXPECT_EQ(result[i].row[0], i);
901 }
902 {
903 auto database = SQL::Database::construct(db_name);
904 EXPECT(!database->open().is_error());
905
906 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
907 EXPECT_EQ(result.size(), 4u);
908
909 for (auto i = 0u; i < result.size(); ++i)
910 EXPECT_EQ(result[i].row[0], i);
911 }
912}
913
914TEST_CASE(delete_all_rows)
915{
916 ScopeGuard guard([]() { unlink(db_name); });
917 {
918 auto database = SQL::Database::construct(db_name);
919 EXPECT(!database->open().is_error());
920
921 create_table(database);
922 for (auto count = 0; count < 10; ++count) {
923 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
924 EXPECT_EQ(result.size(), 1u);
925 }
926
927 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
928 EXPECT_EQ(result.size(), 10u);
929 }
930 {
931 auto database = SQL::Database::construct(db_name);
932 EXPECT(!database->open().is_error());
933
934 execute(database, "DELETE FROM TestSchema.TestTable;");
935
936 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
937 EXPECT(result.is_empty());
938 }
939 {
940 auto database = SQL::Database::construct(db_name);
941 EXPECT(!database->open().is_error());
942
943 auto result = execute(database, "SELECT * FROM TestSchema.TestTable;");
944 EXPECT(result.is_empty());
945 }
946}
947
948TEST_CASE(update_single_row)
949{
950 ScopeGuard guard([]() { unlink(db_name); });
951 {
952 auto database = SQL::Database::construct(db_name);
953 EXPECT(!database->open().is_error());
954
955 create_table(database);
956 for (auto count = 0; count < 10; ++count) {
957 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
958 EXPECT_EQ(result.size(), 1u);
959 }
960
961 execute(database, "UPDATE TestSchema.TestTable SET IntColumn=123456 WHERE (TextColumn = 'T3');");
962
963 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
964 EXPECT_EQ(result.size(), 10u);
965
966 for (auto i = 0u; i < 10; ++i) {
967 if (i < 3)
968 EXPECT_EQ(result[i].row[0], i);
969 else if (i < 9)
970 EXPECT_EQ(result[i].row[0], i + 1);
971 else
972 EXPECT_EQ(result[i].row[0], 123456);
973 }
974 }
975 {
976 auto database = SQL::Database::construct(db_name);
977 EXPECT(!database->open().is_error());
978
979 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
980 EXPECT_EQ(result.size(), 10u);
981
982 for (auto i = 0u; i < 10; ++i) {
983 if (i < 3)
984 EXPECT_EQ(result[i].row[0], i);
985 else if (i < 9)
986 EXPECT_EQ(result[i].row[0], i + 1);
987 else
988 EXPECT_EQ(result[i].row[0], 123456);
989 }
990 }
991}
992
993TEST_CASE(update_multiple_rows)
994{
995 ScopeGuard guard([]() { unlink(db_name); });
996 {
997 auto database = SQL::Database::construct(db_name);
998 EXPECT(!database->open().is_error());
999
1000 create_table(database);
1001 for (auto count = 0; count < 10; ++count) {
1002 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
1003 EXPECT_EQ(result.size(), 1u);
1004 }
1005
1006 execute(database, "UPDATE TestSchema.TestTable SET IntColumn=123456 WHERE (IntColumn > 4);");
1007
1008 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
1009 EXPECT_EQ(result.size(), 10u);
1010
1011 for (auto i = 0u; i < 10; ++i) {
1012 if (i < 5)
1013 EXPECT_EQ(result[i].row[0], i);
1014 else
1015 EXPECT_EQ(result[i].row[0], 123456);
1016 }
1017 }
1018 {
1019 auto database = SQL::Database::construct(db_name);
1020 EXPECT(!database->open().is_error());
1021
1022 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
1023 EXPECT_EQ(result.size(), 10u);
1024
1025 for (auto i = 0u; i < 10; ++i) {
1026 if (i < 5)
1027 EXPECT_EQ(result[i].row[0], i);
1028 else
1029 EXPECT_EQ(result[i].row[0], 123456);
1030 }
1031 }
1032}
1033
1034TEST_CASE(update_all_rows)
1035{
1036 ScopeGuard guard([]() { unlink(db_name); });
1037 {
1038 auto database = SQL::Database::construct(db_name);
1039 EXPECT(!database->open().is_error());
1040
1041 create_table(database);
1042 for (auto count = 0; count < 10; ++count) {
1043 auto result = execute(database, DeprecatedString::formatted("INSERT INTO TestSchema.TestTable VALUES ( 'T{}', {} );", count, count));
1044 EXPECT_EQ(result.size(), 1u);
1045 }
1046
1047 execute(database, "UPDATE TestSchema.TestTable SET IntColumn=123456;");
1048
1049 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
1050 EXPECT_EQ(result.size(), 10u);
1051
1052 for (auto i = 0u; i < 10; ++i)
1053 EXPECT_EQ(result[i].row[0], 123456);
1054 }
1055 {
1056 auto database = SQL::Database::construct(db_name);
1057 EXPECT(!database->open().is_error());
1058
1059 auto result = execute(database, "SELECT IntColumn FROM TestSchema.TestTable ORDER BY IntColumn;");
1060 EXPECT_EQ(result.size(), 10u);
1061
1062 for (auto i = 0u; i < 10; ++i)
1063 EXPECT_EQ(result[i].row[0], 123456);
1064 }
1065}
1066
1067}