1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: TestSQLiteDatabase.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 /*-------------------------------------------------------------------------
16 Copyright 2008 Sandia Corporation.
17 Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
18 the U.S. Government retains certain rights in this software.
19 -------------------------------------------------------------------------*/
20 // .SECTION Thanks
21 // Thanks to Andrew Wilson from Sandia National Laboratories for implementing
22 // this test.
23
24 #include "DatabaseSchemaWith2Tables.h"
25 #include "vtkRowQueryToTable.h"
26 #include "vtkSQLDatabaseSchema.h"
27 #include "vtkSQLQuery.h"
28 #include "vtkSQLiteDatabase.h"
29 #include "vtkSmartPointer.h"
30 #include "vtkStdString.h"
31 #include "vtkTable.h"
32 #include "vtkVariant.h"
33 #include "vtkVariantArray.h"
34
35 #include "vtkTestErrorObserver.h"
36
37 #include <vector>
38
TestSQLiteDatabase(int,char * [])39 int TestSQLiteDatabase(int /*argc*/, char* /*argv*/[])
40 {
41 bool status;
42
43 cerr << ">>>>> Testing bad input." << endl;
44
45 vtkSQLDatabase* db0 = vtkSQLDatabase::CreateFromURL(nullptr);
46 if (db0)
47 {
48 cerr << "ERROR: Created a database from a nullptr URL! How?" << endl;
49 db0->Delete();
50 return 1;
51 }
52
53 cerr << ">>>>> Testing creation modes." << endl;
54
55 vtkSmartPointer<vtkTest::ErrorObserver> errorObserver =
56 vtkSmartPointer<vtkTest::ErrorObserver>::New();
57 vtkSmartPointer<vtkTest::ErrorObserver> queryObserver =
58 vtkSmartPointer<vtkTest::ErrorObserver>::New();
59
60 vtkSQLiteDatabase* db1 =
61 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://local.db"));
62
63 status = db1->Open("", vtkSQLiteDatabase::CREATE_OR_CLEAR);
64 vtkSQLQuery* query1 = db1->GetQueryInstance();
65 query1->SetQuery("CREATE TABLE test (id INTEGER)");
66 if (!query1->Execute())
67 {
68 cerr << "Create query failed" << endl;
69 return 1;
70 }
71 if (!status)
72 {
73 cerr << "Couldn't open database using CREATE_OR_CLEAR.\n";
74 return 1;
75 }
76 db1->Delete();
77 query1->Delete();
78
79 vtkSQLiteDatabase* db2 =
80 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://local.db"));
81 db2->AddObserver(vtkCommand::ErrorEvent, errorObserver);
82 status = db2->Open("", vtkSQLiteDatabase::CREATE);
83 if (status)
84 {
85 cerr << "Using CREATE on an existing file should have failed but did not.\n";
86 return 1;
87 }
88 int status1 =
89 errorObserver->CheckErrorMessage("You specified creating a database but the file exists");
90 db2->Delete();
91
92 vtkSQLiteDatabase* db3 =
93 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://local.db"));
94 status = db3->Open("", vtkSQLiteDatabase::USE_EXISTING_OR_CREATE);
95 if (!status)
96 {
97 cerr << "Using USE_EXISTING_OR_CREATE did not work.\n";
98 return 1;
99 }
100 vtkSQLQuery* query3 = db3->GetQueryInstance();
101 query3->SetQuery("SELECT * from test");
102 if (!query3->Execute())
103 {
104 cerr << "Select query failed" << endl;
105 return 1;
106 }
107 db3->Delete();
108 query3->Delete();
109
110 vtkSQLiteDatabase* db4 =
111 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://local.db"));
112 status = db4->Open("", vtkSQLiteDatabase::CREATE_OR_CLEAR);
113 if (!status)
114 {
115 cerr << "Using CREATE_OR_CLEAR did not work.\n";
116 return 1;
117 }
118 vtkSQLQuery* query4 = db4->GetQueryInstance();
119 query4->AddObserver(vtkCommand::ErrorEvent, queryObserver);
120 query4->SetQuery("SELECT * from test");
121 if (query4->Execute())
122 {
123 cerr << "Select query succeeded when it shouldn't have." << endl;
124 return 1;
125 }
126 status1 += queryObserver->CheckErrorMessage("Query is not null but prepared statement is");
127 db4->Delete();
128 query4->Delete();
129
130 cerr << ">>>>> Testing database functions" << endl;
131
132 vtkSQLiteDatabase* db =
133 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://:memory:"));
134 status = db->Open("");
135
136 if (!status)
137 {
138 cerr << "Couldn't open database.\n";
139 return 1;
140 }
141
142 vtkSQLQuery* query = db->GetQueryInstance();
143
144 vtkStdString createQuery(
145 "CREATE TABLE IF NOT EXISTS people (name TEXT, age INTEGER, weight FLOAT)");
146 cout << createQuery << endl;
147 query->SetQuery(createQuery.c_str());
148 if (!query->Execute())
149 {
150 cerr << "Create query failed" << endl;
151 return 1;
152 }
153
154 int i;
155 for (i = 0; i < 20; i++)
156 {
157 char insertQuery[200];
158 snprintf(insertQuery, sizeof(insertQuery),
159 "INSERT INTO people (name, age, weight) VALUES('John Doe %d', %d, %f)", i, i, 10.1 * i);
160 cout << insertQuery << endl;
161 query->SetQuery(insertQuery);
162 if (!query->Execute())
163 {
164 cerr << "Insert query " << i << " failed" << endl;
165 return 1;
166 }
167 }
168
169 const char* placeholders = "INSERT INTO people (name, age, weight) VALUES (?, ?, ?)";
170 query->SetQuery(placeholders);
171 for (i = 21; i < 40; i++)
172 {
173 char name[20];
174 snprintf(name, sizeof(name), "John Doe %d", i);
175 bool bind1 = query->BindParameter(0, name);
176 bool bind2 = query->BindParameter(1, i);
177 bool bind3 = query->BindParameter(2, 10.1 * i);
178 if (!(bind1 && bind2 && bind3))
179 {
180 cerr << "Parameter binding failed on query " << i << ": " << bind1 << " " << bind2 << " "
181 << bind3 << endl;
182 return 1;
183 }
184 cout << query->GetQuery() << endl;
185 if (!query->Execute())
186 {
187 cerr << "Insert query " << i << " failed" << endl;
188 return 1;
189 }
190 }
191
192 const char* queryText = "SELECT name, age, weight FROM people WHERE age <= 20";
193 query->SetQuery(queryText);
194 cerr << endl << "Running query: " << query->GetQuery() << endl;
195
196 cerr << endl << "Using vtkSQLQuery directly to execute query:" << endl;
197 if (!query->Execute())
198 {
199 cerr << "Query failed" << endl;
200 return 1;
201 }
202
203 for (int col = 0; col < query->GetNumberOfFields(); col++)
204 {
205 if (col > 0)
206 {
207 cerr << ", ";
208 }
209 cerr << query->GetFieldName(col);
210 }
211 cerr << endl;
212 while (query->NextRow())
213 {
214 for (int field = 0; field < query->GetNumberOfFields(); field++)
215 {
216 if (field > 0)
217 {
218 cerr << ", ";
219 }
220 cerr << query->DataValue(field).ToString().c_str();
221 }
222 cerr << endl;
223 }
224
225 cerr << endl << "Using vtkSQLQuery to execute query and retrieve by row:" << endl;
226 if (!query->Execute())
227 {
228 cerr << "Query failed" << endl;
229 return 1;
230 }
231 for (int col = 0; col < query->GetNumberOfFields(); col++)
232 {
233 if (col > 0)
234 {
235 cerr << ", ";
236 }
237 cerr << query->GetFieldName(col);
238 }
239 cerr << endl;
240 vtkVariantArray* va = vtkVariantArray::New();
241 while (query->NextRow(va))
242 {
243 for (int field = 0; field < va->GetNumberOfValues(); field++)
244 {
245 if (field > 0)
246 {
247 cerr << ", ";
248 }
249 cerr << va->GetValue(field).ToString().c_str();
250 }
251 cerr << endl;
252 }
253 va->Delete();
254
255 cerr << endl << "Using vtkRowQueryToTable to execute query:" << endl;
256 vtkRowQueryToTable* reader = vtkRowQueryToTable::New();
257 reader->SetQuery(query);
258 reader->Update();
259 vtkTable* table = reader->GetOutput();
260 for (vtkIdType col = 0; col < table->GetNumberOfColumns(); col++)
261 {
262 table->GetColumn(col)->Print(cerr);
263 }
264 cerr << endl;
265 for (vtkIdType row = 0; row < table->GetNumberOfRows(); row++)
266 {
267 for (vtkIdType col = 0; col < table->GetNumberOfColumns(); col++)
268 {
269 vtkVariant v = table->GetValue(row, col);
270 cerr << "row " << row << ", col " << col << " - " << v.ToString() << " ("
271 << vtkImageScalarTypeNameMacro(v.GetType()) << ")" << endl;
272 }
273 }
274
275 reader->Delete();
276 query->Delete();
277 db->Delete();
278
279 // ----------------------------------------------------------------------
280 // Testing transformation of a schema into a SQLite database
281
282 // 1. Create the schema
283 DatabaseSchemaWith2Tables schema;
284
285 // 2. Convert the schema into a SQLite database
286 cerr << "@@ Converting the schema into a SQLite database...";
287
288 vtkSQLiteDatabase* dbSch =
289 vtkSQLiteDatabase::SafeDownCast(vtkSQLDatabase::CreateFromURL("sqlite://:memory:"));
290 status = dbSch->Open("");
291
292 if (!status)
293 {
294 cerr << "Couldn't open database.\n";
295 return 1;
296 }
297
298 status = dbSch->EffectSchema(schema.GetSchema());
299 if (!status)
300 {
301 cerr << "Could not effect test schema.\n";
302 return 1;
303 }
304 cerr << " done." << endl;
305
306 // 3. Count tables of the newly created database
307 cerr << "@@ Fetching table names of the newly created database:\n";
308
309 query = dbSch->GetQueryInstance();
310
311 query->SetQuery("SELECT name FROM sqlite_master WHERE type = \"table\"");
312 if (!query->Execute())
313 {
314 cerr << "Query failed" << endl;
315 return 1;
316 }
317
318 std::vector<vtkStdString> tables;
319 int tblHandle = 0;
320 for (; query->NextRow(); ++tblHandle)
321 {
322 vtkStdString tblNameSch(schema->GetTableNameFromHandle(tblHandle));
323 vtkStdString tblNameDB(query->DataValue(0).ToString());
324 cerr << " " << tblNameDB << "\n";
325
326 if (tblNameDB != tblNameSch)
327 {
328 cerr << "Fetched an incorrect name: " << tblNameDB << " != " << tblNameSch << endl;
329 return 1;
330 }
331
332 tables.push_back(tblNameDB);
333 }
334
335 if (tblHandle != schema->GetNumberOfTables())
336 {
337 cerr << "Found an incorrect number of tables: " << tblHandle
338 << " != " << schema->GetNumberOfTables() << endl;
339 return 1;
340 }
341
342 cerr << " " << tblHandle << " found.\n";
343
344 // 4. Test EscapeString.
345 cerr << "@@ Escaping a naughty string...";
346
347 vtkStdString queryStr = "INSERT INTO atable (somename,somenmbr) VALUES ( " +
348 query->EscapeString(vtkStdString("Str\"ang'eS\ntring"), true) + ", 2 )";
349 query->SetQuery(queryStr);
350 if (!query->Execute())
351 {
352 cerr << "Query failed" << endl;
353 query->Delete();
354 db->Delete();
355 return 1;
356 }
357
358 cerr << " done." << endl;
359
360 // 5. Read back the escaped string to verify it worked.
361 cerr << "@@ Reading it back... <";
362
363 queryStr = "SELECT somename FROM atable WHERE somenmbr=2";
364 query->SetQuery(queryStr);
365 if (!query->Execute())
366 {
367 cerr << "Query failed" << endl;
368 query->Delete();
369 db->Delete();
370 return 1;
371 }
372
373 if (!query->NextRow())
374 {
375 cerr << "Query returned no results" << endl;
376 query->Delete();
377 db->Delete();
378 return 1;
379 }
380
381 cerr << query->DataValue(0).ToString().c_str() << "> ";
382 cerr << " done." << endl;
383
384 // 6. Drop tables
385 cerr << "@@ Dropping these tables...";
386
387 for (std::vector<vtkStdString>::iterator it = tables.begin(); it != tables.end(); ++it)
388 {
389 queryStr = "DROP TABLE ";
390 queryStr += *it;
391 query->SetQuery(queryStr);
392
393 if (!query->Execute())
394 {
395 cerr << "Query failed" << endl;
396 return 1;
397 }
398 }
399
400 cerr << " done." << endl;
401
402 // Clean up
403 dbSch->Delete();
404 query->Delete();
405
406 return 0;
407 }
408