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