1 /*
2  * Copyright (C) 2011 - 2012 Vivien Malerba <malerba@gnome-db.org>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */
18 #include <libgda/libgda.h>
19 #include <virtual/libgda-virtual.h>
20 #include <sql-parser/gda-sql-parser.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #define NTHREADS 50
25 
26 typedef enum {
27 	ACTION_COMPARE,
28 	ACTION_EXPORT
29 } Action;
30 
31 static GdaDataModel *run_sql_select (GdaConnection *cnc, const gchar *sql,
32 				     gboolean iter_only, GError **error);
33 static gboolean run_sql_non_select (GdaConnection *cnc, const gchar *sql, GdaSet *params, GError **error);
34 static GdaDataModel *assert_run_sql_select (GdaConnection *cnc, const gchar *sql,
35 					    Action action, const gchar *compare_file);
36 static void assert_run_sql_non_select (GdaConnection *cnc, const gchar *sql, GdaSet *params);
37 GdaDataModel *load_from_file (const gchar *filename);
38 static void assert_data_model_equal (GdaDataModel *model, GdaDataModel *ref);
39 
40 static GdaConnection *open_destination_connection (void);
41 static void check_update_delete (GdaConnection *virtual);
42 static void check_simultanous_select_random (GdaConnection *virtual);
43 static void check_simultanous_select_forward (GdaConnection *virtual);
44 static void check_threads_select_random (GdaConnection *virtual);
45 static void check_date (GdaConnection *virtual);
46 
47 int
main(int argc,char * argv[])48 main (int argc, char *argv[])
49 {
50 	GError *error = NULL;
51 	GdaConnection *virtual, *out_cnc;
52 	GdaVirtualProvider *provider;
53 	gchar *file;
54 
55 	gda_init ();
56 
57 	provider = gda_vprovider_hub_new ();
58 	virtual = gda_virtual_connection_open (provider, NULL);
59 	g_assert (virtual);
60 
61 	/* load CSV data models */
62 	GdaDataModel *country_model, *city_model;
63 	GdaSet *options = gda_set_new_inline (2, "TITLE_AS_FIRST_LINE", G_TYPE_BOOLEAN, TRUE,
64 					      "G_TYPE_2", G_TYPE_GTYPE, G_TYPE_INT);
65 	file = g_build_filename (CHECK_FILES, "tests", "data-models", "city.csv", NULL);
66 	city_model = gda_data_model_import_new_file (file, TRUE, options);
67 	g_free (file);
68 	file = g_build_filename (CHECK_FILES, "tests", "data-models", "country.csv", NULL);
69 	country_model = gda_data_model_import_new_file (file, TRUE, options);
70 	g_free (file);
71 	g_object_unref (options);
72 
73 	/* Add data models to connection */
74 	if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (virtual), city_model, "city", &error))
75 		g_error ("Add city model error: %s\n", error && error->message ? error->message : "no detail");
76 	if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (virtual), country_model, "country", &error))
77 		g_error ("Add country model error: %s\n", error && error->message ? error->message : "no detail");
78 
79 	/* SQLite connection for outputs */
80         out_cnc = open_destination_connection ();
81 
82 	/* adding connections to the virtual connection */
83         if (!gda_vconnection_hub_add (GDA_VCONNECTION_HUB (virtual), out_cnc, "out", &error)) {
84                 g_print ("Could not add connection to virtual connection: %s\n",
85                          error && error->message ? error->message : "No detail");
86                 exit (1);
87         }
88 
89 	check_update_delete (virtual);
90 
91 	g_print ("*** Copying data into 'countries' virtual table...\n");
92 	assert_run_sql_non_select (virtual, "INSERT INTO out.countries SELECT * FROM country", NULL);
93 #if HAVE_SQLITE
94 	check_simultanous_select_random (virtual);
95 #endif
96 	check_simultanous_select_forward (virtual);
97 	check_threads_select_random (virtual);
98 	check_date (virtual);
99 
100         gda_connection_close (virtual);
101         gda_connection_close (out_cnc);
102 
103 	g_print ("All Ok\n");
104         return 0;
105 }
106 
107 GdaConnection *
open_destination_connection(void)108 open_destination_connection (void)
109 {
110         /* create connection */
111         GdaConnection *cnc;
112         GError *error = NULL;
113         cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=vcnc",
114                                                NULL,
115                                                GDA_CONNECTION_OPTIONS_NONE,
116                                                &error);
117         if (!cnc) {
118                 g_print ("Could not open connection to local SQLite database: %s\n",
119                          error && error->message ? error->message : "No detail");
120                 exit (1);
121         }
122 
123         /* table "cities" */
124         assert_run_sql_non_select (cnc, "DROP table IF EXISTS cities", NULL);
125         assert_run_sql_non_select (cnc, "CREATE table cities (name string not NULL primary key, countrycode string not null, population int)", NULL);
126 
127         /* table "countries" */
128         assert_run_sql_non_select (cnc, "DROP table IF EXISTS countries", NULL);
129         assert_run_sql_non_select (cnc, "CREATE table countries (code string not null primary key, name string not null)", NULL);
130 
131 	/* table "misc" */
132         assert_run_sql_non_select (cnc, "DROP table IF EXISTS misc", NULL);
133         assert_run_sql_non_select (cnc, "CREATE table misc (ts timestamp, adate date, atime time)", NULL);
134 
135         return cnc;
136 }
137 
138 static GdaDataModel *
run_sql_select(GdaConnection * cnc,const gchar * sql,gboolean iter_only,GError ** error)139 run_sql_select (GdaConnection *cnc, const gchar *sql, gboolean iter_only, GError **error)
140 {
141 	GdaStatement *stmt;
142 	GdaDataModel *res;
143 	GdaSqlParser *parser;
144 
145 	parser = gda_connection_create_parser (cnc);
146 	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
147 	g_object_unref (parser);
148 
149 	res = gda_connection_statement_execute_select_full (cnc, stmt, NULL,
150 							    iter_only ? GDA_STATEMENT_MODEL_CURSOR_FORWARD :
151 							    GDA_STATEMENT_MODEL_RANDOM_ACCESS,
152 							    NULL, error);
153         g_object_unref (stmt);
154 	return res;
155 }
156 
157 
158 static gboolean
run_sql_non_select(GdaConnection * cnc,const gchar * sql,GdaSet * params,GError ** error)159 run_sql_non_select (GdaConnection *cnc, const gchar *sql, GdaSet *params, GError **error)
160 {
161 	GdaStatement *stmt;
162         gint nrows;
163         GdaSqlParser *parser;
164 
165         parser = gda_connection_create_parser (cnc);
166         stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
167         g_object_unref (parser);
168 
169         nrows = gda_connection_statement_execute_non_select (cnc, stmt, params, NULL, error);
170         g_object_unref (stmt);
171         if (nrows == -1)
172 		return FALSE;
173 	else
174 		return TRUE;
175 }
176 
177 static void
assert_data_model_equal(GdaDataModel * model,GdaDataModel * ref)178 assert_data_model_equal (GdaDataModel *model, GdaDataModel *ref)
179 {
180 	GdaDataComparator *comp;
181 	GError *error = NULL;
182 	comp = GDA_DATA_COMPARATOR (gda_data_comparator_new (ref, model));
183 	if (! gda_data_comparator_compute_diff (comp, &error)) {
184 		g_print ("Error comparing data models: %s\n",
185 			 error && error->message ? error->message : "No detail");
186 		exit (1);
187 	}
188 	if (gda_data_comparator_get_n_diffs (comp) > 0) {
189 		g_print ("Data models differ!\n");
190 		g_print ("Expected:\n");
191 		gda_data_model_dump (ref, NULL);
192 		g_print ("Got:\n");
193 		gda_data_model_dump (model, NULL);
194 		exit (1);
195 	}
196 	g_object_unref (comp);
197 }
198 
199 static GdaDataModel *
assert_run_sql_select(GdaConnection * cnc,const gchar * sql,Action action,const gchar * compare_file)200 assert_run_sql_select (GdaConnection *cnc, const gchar *sql, Action action, const gchar *compare_file)
201 {
202 	GError *error = NULL;
203 	GdaDataModel *model = run_sql_select (cnc, sql, FALSE, &error);
204 	if (!model) {
205 		g_print ("Error executing [%s]: %s\n",
206 			 sql,
207 			 error && error->message ? error->message : "No detail");
208 		exit (1);
209 	}
210 
211 	gda_data_model_dump (model, NULL);
212 	if (compare_file) {
213 		gchar *file;
214 		file = g_build_filename (CHECK_FILES, "tests", "data-models", compare_file, NULL);
215 		if (action == ACTION_EXPORT) {
216 			if (! gda_data_model_export_to_file (model, GDA_DATA_MODEL_IO_DATA_ARRAY_XML,
217 							     file,
218 							     NULL, 0, NULL, 0, NULL, &error)) {
219 				g_print ("Error exporting to file '%s': %s\n",
220 					 file,
221 					 error && error->message ? error->message : "No detail");
222 				exit (1);
223 			}
224 			g_print ("Generated '%s'\n", file);
225 		}
226 		else if (action == ACTION_COMPARE) {
227 			GdaDataModel *ref;
228 			ref = load_from_file (compare_file);
229 			assert_data_model_equal (model, ref);
230 			g_object_unref (ref);
231 		}
232 		else
233 			g_assert_not_reached ();
234 		g_free (file);
235 	}
236 
237 	return model;
238 }
239 
240 static void
assert_run_sql_non_select(GdaConnection * cnc,const gchar * sql,GdaSet * params)241 assert_run_sql_non_select (GdaConnection *cnc, const gchar *sql, GdaSet *params)
242 {
243 	GError *error = NULL;
244 	if (! run_sql_non_select (cnc, sql, params, &error)) {
245 		g_print ("Error executing [%s]: %s\n",
246 			 sql,
247 			 error && error->message ? error->message : "No detail");
248 		exit (1);
249 	}
250 }
251 
252 GdaDataModel *
load_from_file(const gchar * filename)253 load_from_file (const gchar *filename)
254 {
255 	GdaDataModel *model;
256 	gchar *file;
257 
258 	file = g_build_filename (CHECK_FILES, "tests", "data-models", filename, NULL);
259 	model = gda_data_model_import_new_file (file, TRUE, NULL);
260 	if (gda_data_model_import_get_errors (GDA_DATA_MODEL_IMPORT (model))) {
261 		g_print ("Error loading file '%s'\n", file);
262 		exit (1);
263 	}
264 	g_free (file);
265 	return model;
266 }
267 
268 static void
move_iter_forward(GdaDataModelIter * iter,const gchar * iter_name,gint nb,GdaDataModel * ref,gint start_row)269 move_iter_forward (GdaDataModelIter *iter, const gchar *iter_name, gint nb, GdaDataModel *ref, gint start_row)
270 {
271 	gint i;
272 	for (i = 0; i < nb; i++) {
273 #ifdef DEBUG_PRINT
274 		g_print ("*** moving iter %s forward... ", iter_name);
275 #endif
276 		if (! gda_data_model_iter_move_next (iter)) {
277 			g_print ("Could not move forward at step %d\n", i);
278 			exit (1);
279 		}
280 		else {
281 			const GValue *cvalue;
282 			cvalue = gda_data_model_iter_get_value_at (iter, 0);
283 #ifdef DEBUG_PRINT
284 			gchar *str;
285 			str = gda_value_stringify (cvalue);
286 			g_print ("Col0=[%s]", str);
287 			g_free (str);
288 #endif
289 
290 			if (ref) {
291 				if (gda_data_model_iter_get_row (iter) != (start_row + i)) {
292 					g_print (" Wrong reported row %d instead of %d\n",
293 						 gda_data_model_iter_get_row (iter),  start_row + i);
294 					exit (1);
295 				}
296 				const GValue *rvalue;
297 				rvalue = gda_data_model_get_value_at (ref, 0, start_row + i, NULL);
298 				g_assert (rvalue);
299 				gchar *str1, *str2;
300 				str1 = gda_value_stringify (cvalue);
301 				str2 = gda_value_stringify (rvalue);
302 				if (strcmp (str1, str2)) {
303 					g_print (" Wrong reported value [%s] instead of [%s]\n",
304 						 str1, str2);
305 					exit (1);
306 				}
307 #ifdef DEBUG_PRINT
308 				else
309 					g_print (" Value Ok.");
310 #endif
311 				g_free (str1);
312 				g_free (str2);
313 			}
314 #ifdef DEBUG_PRINT
315 			g_print ("\n");
316 #endif
317 		}
318 	}
319 }
320 
321 static void
check_simultanous_select_random(GdaConnection * virtual)322 check_simultanous_select_random (GdaConnection *virtual)
323 {
324 	GdaDataModel *m1, *m2;
325 	GdaDataModel *refA = NULL, *refB = NULL;
326 	GdaDataModelIter *iter1, *iter2;
327 	GError *error = NULL;
328 
329 	g_print ("*** simultaneous SELECT RANDOM 1\n");
330 	m1 = run_sql_select (virtual, "SELECT * FROM countries WHERE code LIKE 'A%' ORDER BY code",
331 			     FALSE, &error);
332 	if (!m1) {
333 		g_print ("Could not execute SELECT (1): %s\n",
334                          error && error->message ? error->message : "No detail");
335                 exit (1);
336 	}
337 
338 	g_print ("*** simultaneous SELECT RANDOM 2\n");
339 	m2 = run_sql_select (virtual, "SELECT * FROM countries WHERE code LIKE 'B%' ORDER BY code",
340 			     FALSE, &error);
341 	if (!m2) {
342 		g_print ("Could not execute SELECT (2): %s\n",
343                          error && error->message ? error->message : "No detail");
344                 exit (1);
345 	}
346 
347 	gda_data_model_dump (m2, NULL);
348 	gda_data_model_dump (m1, NULL);
349 
350 /*#define EXPORT*/
351 #ifdef EXPORT
352 	gchar *file;
353 	file = g_build_filename (CHECK_FILES, "tests", "data-models", "countriesA.xml", NULL);
354 	if (! gda_data_model_export_to_file (m1, GDA_DATA_MODEL_IO_DATA_ARRAY_XML,
355 					     file,
356 					     NULL, 0, NULL, 0, NULL, &error)) {
357 		g_print ("Error exporting to file '%s': %s\n",
358 			 file,
359 			 error && error->message ? error->message : "No detail");
360 		exit (1);
361 	}
362 	g_print ("Generated '%s'\n", file);
363 	g_free (file);
364 
365 	file = g_build_filename (CHECK_FILES, "tests", "data-models", "countriesB.xml", NULL);
366 	if (! gda_data_model_export_to_file (m2, GDA_DATA_MODEL_IO_DATA_ARRAY_XML,
367 					     file,
368 					     NULL, 0, NULL, 0, NULL, &error)) {
369 		g_print ("Error exporting to file '%s': %s\n",
370 			 file,
371 			 error && error->message ? error->message : "No detail");
372 		exit (1);
373 	}
374 	g_print ("Generated '%s'\n", file);
375 	g_free (file);
376 #else
377 	refA = load_from_file ("countriesA.xml");
378 	assert_data_model_equal (m1, refA);
379 
380 	refB = load_from_file ("countriesB.xml");
381 	assert_data_model_equal (m2, refB);
382 #endif
383 
384 	iter1 = gda_data_model_create_iter (m1);
385 	g_print ("*** simultaneous iter 1 %p\n", iter1);
386 
387 	iter2 = gda_data_model_create_iter (m2);
388 	g_print ("*** simultaneous iter 2 %p\n", iter2);
389 
390 	move_iter_forward (iter1, "iter1", 10, refA, 0);
391 	move_iter_forward (iter2, "iter2", 3, refB, 0);
392 	move_iter_forward (iter1, "iter1", 3, refA, 10);
393 	move_iter_forward (iter2, "iter2", 2, refB, 3);
394 
395 	g_object_unref (iter1);
396 	g_object_unref (iter2);
397 
398 	g_object_unref (m1);
399 	g_object_unref (m2);
400 #ifndef EXPORT
401 	g_object_unref (refA);
402 	g_object_unref (refB);
403 #endif
404 }
405 
406 static void
check_simultanous_select_forward(GdaConnection * virtual)407 check_simultanous_select_forward (GdaConnection *virtual)
408 {
409 	GdaDataModel *m1, *m2;
410 	GdaDataModel *refA, *refB;
411 	GdaDataModelIter *iter1, *iter2;
412 	GError *error = NULL;
413 
414 	g_print ("*** simultaneous SELECT FORWARD 1\n");
415 	m1 = run_sql_select (virtual, "SELECT * FROM countries WHERE code LIKE 'A%' ORDER BY code",
416 			     TRUE, &error);
417 	if (!m1) {
418 		g_print ("Could not execute SELECT with forward iter only (1): %s\n",
419                          error && error->message ? error->message : "No detail");
420                 exit (1);
421 	}
422 
423 	g_print ("*** simultaneous SELECT FORWARD 2\n");
424 	m2 = run_sql_select (virtual, "SELECT * FROM countries WHERE code LIKE 'B%' ORDER BY code",
425 			     TRUE, &error);
426 	if (!m2) {
427 		g_print ("Could not execute SELECT with forward iter only (2): %s\n",
428                          error && error->message ? error->message : "No detail");
429                 exit (1);
430 	}
431 
432 	refA = load_from_file ("countriesA.xml");
433 	refB = load_from_file ("countriesB.xml");
434 
435 	iter1 = gda_data_model_create_iter (m1);
436 	g_print ("*** simultaneous iter 1 %p\n", iter1);
437 
438 	iter2 = gda_data_model_create_iter (m2);
439 	g_print ("*** simultaneous iter 2 %p\n", iter2);
440 
441 	move_iter_forward (iter1, "iter1", 10, refA, 0);
442 	if (gda_data_model_iter_move_prev (iter1)) {
443 		g_print ("Iter should not be allowed to move backward!\n");
444                 exit (1);
445 	}
446 	move_iter_forward (iter2, "iter2", 3, refB, 0);
447 	move_iter_forward (iter1, "iter1", 3, refA, 10);
448 	move_iter_forward (iter2, "iter2", 2, refB, 3);
449 
450 	g_object_unref (iter1);
451 	g_object_unref (iter2);
452 
453 	g_object_unref (refA);
454 	g_object_unref (refB);
455 
456 	g_object_unref (m1);
457 	g_object_unref (m2);
458 }
459 
460 
461 static void
check_update_delete(GdaConnection * virtual)462 check_update_delete (GdaConnection *virtual)
463 {
464 	/* Check DELETE and UPDATE */
465 	g_print ("*** Copying data into virtual 'cities' table...\n");
466 	assert_run_sql_non_select (virtual, "INSERT INTO out.cities SELECT * FROM city WHERE population >= 500000", NULL);
467 	g_print ("*** Showing list of cities WHERE population >= 1000000\n");
468 	assert_run_sql_select (virtual, "SELECT * FROM out.cities WHERE population >= 1000000 "
469 			       "ORDER BY name", ACTION_COMPARE, "cities1.xml");
470 
471 	g_print ("*** Deleting data where population < 2000000...\n");
472 	assert_run_sql_non_select (virtual, "DELETE FROM out.cities WHERE population < 2000000", NULL);
473 
474 	g_print ("*** Showing (shorter) list of cities WHERE population >= 1000000\n");
475 	assert_run_sql_select (virtual, "SELECT * FROM out.cities WHERE population >= 1000000 "
476 			       "ORDER BY name", ACTION_COMPARE, "cities2.xml");
477 
478 	g_print ("*** Updating data where population > 3000000...\n");
479 	assert_run_sql_non_select (virtual, "UPDATE out.cities SET population = 3000000 WHERE "
480 				   "population >= 3000000", NULL);
481 
482 	g_print ("*** Showing list of cities WHERE population >= 2100000\n");
483 	assert_run_sql_select (virtual, "SELECT * FROM out.cities WHERE population >= 2100000 "
484 			       "ORDER BY name", ACTION_COMPARE, "cities3.xml");
485 }
486 
487 typedef struct {
488 	GThread  *thread;
489 	gint      th_id;
490 	GdaConnection *virtual;
491 } ThData;
492 
493 static gboolean
test_multiple_threads(GThreadFunc func,GdaConnection * virtual)494 test_multiple_threads (GThreadFunc func, GdaConnection *virtual)
495 {
496 	ThData data[NTHREADS];
497 	gint i;
498 
499 	for (i = 0; i < NTHREADS; i++) {
500 		ThData *d = &(data[i]);
501 		d->th_id = i;
502 		d->virtual = virtual;
503 	}
504 
505 	for (i = 0; i < NTHREADS; i++) {
506 		ThData *d = &(data[i]);
507 #ifdef DEBUG_PRINT
508 		g_print ("Running thread %d\n", d->th_id);
509 #endif
510 		d->thread = g_thread_create (func, d, TRUE, NULL);
511 	}
512 
513 	for (i = 0; i < NTHREADS; i++) {
514 		ThData *d = &(data[i]);
515 		g_thread_join (d->thread);
516 	}
517 
518 	g_print ("All threads finished\n");
519 	return TRUE;
520 }
521 
522 /* executed in another thread */
523 gpointer
threads_select_random_start_thread(ThData * data)524 threads_select_random_start_thread (ThData *data)
525 {
526 	GdaDataModel *model;
527 	GdaDataModel *ref;
528 	GdaDataModelIter *iter;
529 	GError *error = NULL;
530 	GThread *self;
531 	gchar *str;
532 
533 	self = g_thread_self ();
534 	g_print ("*** sub thread %p SELECT RANDOM\n", self);
535 	model = run_sql_select (data->virtual, "SELECT * FROM countries WHERE code LIKE 'A%' ORDER BY code",
536 				FALSE, &error);
537 	if (!model) {
538 		g_print ("Could not execute SELECT with forward iter only: %s\n",
539                          error && error->message ? error->message : "No detail");
540                 exit (1);
541 	}
542 
543 	ref = load_from_file ("countriesA.xml");
544 	assert_data_model_equal (model, ref);
545 
546 	iter = gda_data_model_create_iter (model);
547 
548 	str = g_strdup_printf ("iter thread %p", self);
549 	move_iter_forward (iter, str, 10, ref, 0);
550 	move_iter_forward (iter, str, 3, ref, 10);
551 	g_free (str);
552 
553 	g_object_unref (iter);
554 	g_object_unref (model);
555 	g_object_unref (ref);
556 	g_print ("thread %p finished\n", self);
557 
558 	return NULL;
559 }
560 
561 static void
check_threads_select_random(GdaConnection * virtual)562 check_threads_select_random (GdaConnection *virtual)
563 {
564 	test_multiple_threads ((GThreadFunc) threads_select_random_start_thread, virtual);
565 }
566 
567 static void
check_date(GdaConnection * virtual)568 check_date (GdaConnection *virtual)
569 {
570 	g_print ("*** insert dates into 'misc' table...\n");
571 	GdaSet *set;
572 	GdaTimestamp ts = {2011, 01, 31, 12, 34, 56, 0, 0};
573 	GdaTime atime = {13, 45, 59, 0, 0};
574 	GDate *adate;
575 	GdaDataModel *model;
576 	GError *error = NULL;
577 
578 	adate = g_date_new_dmy (23, G_DATE_FEBRUARY, 2010);
579 	set = gda_set_new_inline (3,
580 				  "ts", GDA_TYPE_TIMESTAMP, &ts,
581 				  "adate", G_TYPE_DATE, adate,
582 				  "atime", GDA_TYPE_TIME, &atime);
583 	g_date_free (adate);
584 
585 	assert_run_sql_non_select (virtual, "INSERT INTO out.misc VALUES (##ts::timestamp, "
586 				   "##adate::date, ##atime::time)", set);
587 
588 	g_print ("*** Showing contents of 'misc'\n");
589 	model = assert_run_sql_select (virtual, "SELECT * FROM out.misc",
590 				       ACTION_EXPORT, NULL);
591 	const GValue *cvalue, *exp;
592 	cvalue = gda_data_model_get_value_at (model, 0, 0, &error);
593 	if (! cvalue) {
594 		g_print ("Could not get timestamp value: %s\n",
595                          error && error->message ? error->message : "No detail");
596                 exit (1);
597 	}
598 	exp = gda_set_get_holder_value (set, "ts");
599 	if (gda_value_differ (cvalue, exp)) {
600 		g_print ("Expected value '%s', got '%s'\n",
601 			 gda_value_stringify (exp), gda_value_stringify (cvalue));
602 		exit (1);
603 	}
604 
605 	cvalue = gda_data_model_get_value_at (model, 1, 0, &error);
606 	if (! cvalue) {
607 		g_print ("Could not get timestamp value: %s\n",
608                          error && error->message ? error->message : "No detail");
609                 exit (1);
610 	}
611 	exp = gda_set_get_holder_value (set, "adate");
612 	if (gda_value_differ (cvalue, exp)) {
613 		g_print ("Expected value '%s', got '%s'\n",
614 			 gda_value_stringify (exp), gda_value_stringify (cvalue));
615 		exit (1);
616 	}
617 
618 	cvalue = gda_data_model_get_value_at (model, 2, 0, &error);
619 	if (! cvalue) {
620 		g_print ("Could not get timestamp value: %s\n",
621                          error && error->message ? error->message : "No detail");
622                 exit (1);
623 	}
624 	exp = gda_set_get_holder_value (set, "atime");
625 	if (gda_value_differ (cvalue, exp)) {
626 		g_print ("Expected value '%s', got '%s'\n",
627 			 gda_value_stringify (exp), gda_value_stringify (cvalue));
628 		exit (1);
629 	}
630 
631 	g_object_unref (set);
632 }
633