1 /*
2 * Copyright (C) 2011 Murray Cumming <murrayc@murrayc.com>
3 * Copyright (C) 2011 - 2013 Vivien Malerba <malerba@gnome-db.org>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20
21 #undef GDA_DISABLE_DEPRECATED
22 #include "gda-data-pivot.h"
23
24 #include <string.h>
25 #include <glib/gi18n-lib.h>
26 #include <libgda/gda-enums.h>
27 #include <libgda/gda-holder.h>
28 #include <libgda/gda-data-model.h>
29 #include <libgda/gda-data-model-array.h>
30 #include <libgda/gda-data-model-iter.h>
31 #include <libgda/gda-row.h>
32 #include <libgda/gda-util.h>
33 #include <libgda/gda-blob-op.h>
34 #include <libgda/gda-sql-builder.h>
35 #include <virtual/libgda-virtual.h>
36 #include <sql-parser/gda-sql-parser.h>
37 #include <libgda/sql-parser/gda-sql-statement.h>
38 #include <libgda/gda-debug-macros.h>
39
40 typedef struct {
41 GValue *value;
42 gint column_fields_index;
43 gint data_pos; /* index in pivot->priv->data_fields, or -1 if no index */
44 } ColumnData;
45 static guint column_data_hash (gconstpointer key);
46 static gboolean column_data_equal (gconstpointer a, gconstpointer b);
47 static void column_data_free (ColumnData *cdata);
48
49
50 typedef struct {
51 gint row;
52 gint col;
53 GType gtype;
54 GArray *values; /* array of #GValue, none will be GDA_TYPE_NULL, and there is at least always 1 GValue */
55 GdaDataPivotAggregate aggregate;
56
57 gint nvalues;
58 GValue *data_value;
59 GError *error;
60 } CellData;
61 static guint cell_data_hash (gconstpointer key);
62 static gboolean cell_data_equal (gconstpointer a, gconstpointer b);
63 static void cell_data_free (CellData *cdata);
64 static void cell_data_compute_aggregate (CellData *cdata);
65
66 static GValue *aggregate_get_empty_value (GdaDataPivotAggregate aggregate);
67 static gboolean aggregate_handle_new_value (CellData *cdata, const GValue *new_value);
68
69
70 struct _GdaDataPivotPrivate {
71 GdaDataModel *model; /* data to analyse */
72
73 GdaConnection *vcnc; /* to use data in @model for row and column fields */
74
75 GArray *row_fields; /* array of (gchar *) field specifications */
76 GArray *column_fields; /* array of (gchar *) field specifications */
77 GArray *data_fields; /* array of (gchar *) field specifications */
78 GArray *data_aggregates; /* array of GdaDataPivotAggregate, corresponding to @data_fields */
79
80 /* computed data */
81 GArray *columns; /* Array of GdaColumn objects, for ALL columns! */
82 GdaDataModel *results;
83 GRecMutex provider_mutex;
84 GdaVirtualProvider *virtual_provider;
85 };
86
87 /* properties */
88 enum
89 {
90 PROP_0,
91 PROP_MODEL,
92 };
93
94 #define TABLE_NAME "data"
95
96 static void gda_data_pivot_class_init (GdaDataPivotClass *klass);
97 static void gda_data_pivot_init (GdaDataPivot *model,
98 GdaDataPivotClass *klass);
99 static void gda_data_pivot_dispose (GObject *object);
100 static void gda_data_pivot_finalize (GObject *object);
101
102 static void gda_data_pivot_set_property (GObject *object,
103 guint param_id,
104 const GValue *value,
105 GParamSpec *pspec);
106 static void gda_data_pivot_get_property (GObject *object,
107 guint param_id,
108 GValue *value,
109 GParamSpec *pspec);
110
111 static guint _gda_value_hash (gconstpointer key);
112 static guint _gda_row_hash (gconstpointer key);
113 static gboolean _gda_row_equal (gconstpointer a, gconstpointer b);
114 static gboolean create_vcnc (GdaDataPivot *pivot, GError **error);
115 static gboolean bind_source_model (GdaDataPivot *pivot, GError **error);
116 static void clean_previous_population (GdaDataPivot *pivot);
117
118 /* GdaDataModel interface */
119 static void gda_data_pivot_data_model_init (GdaDataModelIface *iface);
120 static gint gda_data_pivot_get_n_rows (GdaDataModel *model);
121 static gint gda_data_pivot_get_n_columns (GdaDataModel *model);
122 static GdaColumn *gda_data_pivot_describe_column (GdaDataModel *model, gint col);
123 static GdaDataModelAccessFlags gda_data_pivot_get_access_flags(GdaDataModel *model);
124 static const GValue *gda_data_pivot_get_value_at (GdaDataModel *model, gint col, gint row, GError **error);
125
126 static GObjectClass *parent_class = NULL;
127
128 /**
129 * gda_data_pivot_get_type:
130 *
131 * Returns: the #GType of GdaDataPivot.
132 */
133 GType
gda_data_pivot_get_type(void)134 gda_data_pivot_get_type (void)
135 {
136 static GType type = 0;
137
138 if (G_UNLIKELY (type == 0)) {
139 static GMutex registering;
140 static const GTypeInfo info = {
141 sizeof (GdaDataPivotClass),
142 (GBaseInitFunc) NULL,
143 (GBaseFinalizeFunc) NULL,
144 (GClassInitFunc) gda_data_pivot_class_init,
145 NULL,
146 NULL,
147 sizeof (GdaDataPivot),
148 0,
149 (GInstanceInitFunc) gda_data_pivot_init,
150 0
151 };
152
153 static const GInterfaceInfo data_model_info = {
154 (GInterfaceInitFunc) gda_data_pivot_data_model_init,
155 NULL,
156 NULL
157 };
158
159 g_mutex_lock (®istering);
160 if (type == 0) {
161 type = g_type_register_static (G_TYPE_OBJECT, "GdaDataPivot", &info, 0);
162 g_type_add_interface_static (type, GDA_TYPE_DATA_MODEL, &data_model_info);
163 }
164 g_mutex_unlock (®istering);
165 }
166 return type;
167 }
168
169 static void
gda_data_pivot_class_init(GdaDataPivotClass * klass)170 gda_data_pivot_class_init (GdaDataPivotClass *klass)
171 {
172 GObjectClass *object_class = G_OBJECT_CLASS (klass);
173
174 parent_class = g_type_class_peek_parent (klass);
175
176 /* properties */
177 object_class->set_property = gda_data_pivot_set_property;
178 object_class->get_property = gda_data_pivot_get_property;
179 g_object_class_install_property (object_class, PROP_MODEL,
180 g_param_spec_object ("model", NULL, "Data model from which data is analysed",
181 GDA_TYPE_DATA_MODEL,
182 G_PARAM_READABLE | G_PARAM_WRITABLE));
183
184 /* virtual functions */
185 object_class->dispose = gda_data_pivot_dispose;
186 object_class->finalize = gda_data_pivot_finalize;
187 }
188
189 static void
gda_data_pivot_data_model_init(GdaDataModelIface * iface)190 gda_data_pivot_data_model_init (GdaDataModelIface *iface)
191 {
192 iface->i_get_n_rows = gda_data_pivot_get_n_rows;
193 iface->i_get_n_columns = gda_data_pivot_get_n_columns;
194 iface->i_describe_column = gda_data_pivot_describe_column;
195 iface->i_get_access_flags = gda_data_pivot_get_access_flags;
196 iface->i_get_value_at = gda_data_pivot_get_value_at;
197 iface->i_get_attributes_at = NULL;
198
199 iface->i_create_iter = NULL;
200 iface->i_iter_at_row = NULL;
201 iface->i_iter_next = NULL;
202 iface->i_iter_prev = NULL;
203
204 iface->i_set_value_at = NULL;
205 iface->i_iter_set_value = NULL;
206 iface->i_set_values = NULL;
207 iface->i_append_values = NULL;
208 iface->i_append_row = NULL;
209 iface->i_remove_row = NULL;
210 iface->i_find_row = NULL;
211
212 iface->i_set_notify = NULL;
213 iface->i_get_notify = NULL;
214 iface->i_send_hint = NULL;
215 }
216
217 static void
gda_data_pivot_init(GdaDataPivot * model,G_GNUC_UNUSED GdaDataPivotClass * klass)218 gda_data_pivot_init (GdaDataPivot *model, G_GNUC_UNUSED GdaDataPivotClass *klass)
219 {
220 g_return_if_fail (GDA_IS_DATA_PIVOT (model));
221 model->priv = g_new0 (GdaDataPivotPrivate, 1);
222 model->priv->model = NULL;
223 model->priv->virtual_provider = NULL;
224 g_rec_mutex_init (& model->priv->provider_mutex);
225 }
226
227 static void
clean_previous_population(GdaDataPivot * pivot)228 clean_previous_population (GdaDataPivot *pivot)
229 {
230 if (pivot->priv->results) {
231 g_object_unref ((GObject*) pivot->priv->results);
232 pivot->priv->results = NULL;
233 }
234
235 if (pivot->priv->columns) {
236 guint i;
237 for (i = 0; i < pivot->priv->columns->len; i++) {
238 GObject *obj;
239 obj = g_array_index (pivot->priv->columns, GObject*, i);
240 g_object_unref (obj);
241 }
242 g_array_free (pivot->priv->columns, TRUE);
243 pivot->priv->columns = NULL;
244 }
245 }
246
247 static void
gda_data_pivot_dispose(GObject * object)248 gda_data_pivot_dispose (GObject *object)
249 {
250 GdaDataPivot *model = (GdaDataPivot *) object;
251
252 g_return_if_fail (GDA_IS_DATA_PIVOT (model));
253
254 /* free memory */
255 if (model->priv) {
256 clean_previous_population (model);
257
258 if (model->priv->row_fields) {
259 guint i;
260 for (i = 0; i < model->priv->row_fields->len; i++) {
261 gchar *tmp;
262 tmp = g_array_index (model->priv->row_fields, gchar*, i);
263 g_free (tmp);
264 }
265 g_array_free (model->priv->row_fields, TRUE);
266 model->priv->row_fields = NULL;
267 }
268
269 if (model->priv->column_fields) {
270 guint i;
271 for (i = 0; i < model->priv->column_fields->len; i++) {
272 gchar *tmp;
273 tmp = g_array_index (model->priv->column_fields, gchar*, i);
274 g_free (tmp);
275 }
276 g_array_free (model->priv->column_fields, TRUE);
277 model->priv->column_fields = NULL;
278 }
279
280 if (model->priv->data_fields) {
281 guint i;
282 for (i = 0; i < model->priv->data_fields->len; i++) {
283 gchar *tmp;
284 tmp = g_array_index (model->priv->data_fields, gchar*, i);
285 g_free (tmp);
286 }
287 g_array_free (model->priv->data_fields, TRUE);
288 model->priv->data_fields = NULL;
289 }
290
291 if (model->priv->data_aggregates) {
292 g_array_free (model->priv->data_aggregates, TRUE);
293 model->priv->data_aggregates = NULL;
294 }
295
296 if (model->priv->vcnc) {
297 if (G_IS_OBJECT (model->priv->vcnc))
298 g_object_unref (model->priv->vcnc);
299 model->priv->vcnc = NULL;
300 }
301
302 if (model->priv->model) {
303 if (G_IS_OBJECT (model->priv->model))
304 g_object_unref (model->priv->model);
305 model->priv->model = NULL;
306 }
307
308 if (model->priv->virtual_provider) {
309 if (G_IS_OBJECT (model->priv->virtual_provider))
310 g_object_unref (model->priv->virtual_provider);
311 model->priv->model = NULL;
312 }
313 }
314
315 /* chain to parent class */
316 parent_class->dispose (object);
317 }
318
319 static void
gda_data_pivot_finalize(GObject * object)320 gda_data_pivot_finalize (GObject *object)
321 {
322 GdaDataPivot *model = (GdaDataPivot *) object;
323
324 g_return_if_fail (GDA_IS_DATA_PIVOT (model));
325
326 g_rec_mutex_clear (& model->priv->provider_mutex);
327
328 /* free memory */
329 if (model->priv) {
330 g_free (model->priv);
331 model->priv = NULL;
332 }
333
334 /* chain to parent class */
335 parent_class->finalize (object);
336 }
337
338 /* module error */
gda_data_pivot_error_quark(void)339 GQuark gda_data_pivot_error_quark (void)
340 {
341 static GQuark quark;
342 if (!quark)
343 quark = g_quark_from_static_string ("gda_data_pivot_error");
344 return quark;
345 }
346
347 static void
gda_data_pivot_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)348 gda_data_pivot_set_property (GObject *object,
349 guint param_id,
350 const GValue *value,
351 GParamSpec *pspec)
352 {
353 GdaDataPivot *model;
354
355 model = GDA_DATA_PIVOT (object);
356 if (model->priv) {
357 switch (param_id) {
358 case PROP_MODEL: {
359 GdaDataModel *mod = g_value_dup_object (value);
360
361 clean_previous_population (model);
362
363 if (mod) {
364 g_return_if_fail (GDA_IS_DATA_MODEL (mod));
365
366 if (model->priv->model) {
367 if (model->priv->vcnc)
368 gda_vconnection_data_model_remove (GDA_VCONNECTION_DATA_MODEL (model->priv->vcnc),
369 TABLE_NAME, NULL);
370 g_object_unref (model->priv->model);
371 }
372
373 model->priv->model = mod;
374 }
375 break;
376 }
377 default:
378 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
379 break;
380 }
381 }
382 }
383
384 static void
gda_data_pivot_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)385 gda_data_pivot_get_property (GObject *object,
386 guint param_id,
387 GValue *value,
388 GParamSpec *pspec)
389 {
390 GdaDataPivot *model;
391
392 model = GDA_DATA_PIVOT (object);
393 if (model->priv) {
394 switch (param_id) {
395 case PROP_MODEL:
396 g_value_set_object (value, G_OBJECT (model->priv->model));
397 break;
398 default:
399 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
400 break;
401 }
402 }
403 }
404
405 /**
406 * gda_data_pivot_new:
407 * @model: (allow-none): a #GdaDataModel to analyse data from, or %NULL
408 *
409 * Creates a new #GdaDataModel which will contain analysed data from @model.
410 *
411 * Returns: (transfer full): a pointer to the newly created #GdaDataModel.
412 */
413 GdaDataModel *
gda_data_pivot_new(GdaDataModel * model)414 gda_data_pivot_new (GdaDataModel *model)
415 {
416 GdaDataPivot *retmodel;
417
418 g_return_val_if_fail (!model || GDA_IS_DATA_MODEL (model), NULL);
419
420 retmodel = g_object_new (GDA_TYPE_DATA_PIVOT,
421 "model", model, NULL);
422
423 return GDA_DATA_MODEL (retmodel);
424 }
425
426 /*
427 * GdaDataModel interface implementation
428 */
429 static gint
gda_data_pivot_get_n_rows(GdaDataModel * model)430 gda_data_pivot_get_n_rows (GdaDataModel *model)
431 {
432 GdaDataPivot *pivot;
433 g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), -1);
434 pivot = GDA_DATA_PIVOT (model);
435 g_return_val_if_fail (pivot->priv, -1);
436
437 if (pivot->priv->results)
438 return gda_data_model_get_n_rows (pivot->priv->results);
439 else
440 return -1;
441 }
442
443 static gint
gda_data_pivot_get_n_columns(GdaDataModel * model)444 gda_data_pivot_get_n_columns (GdaDataModel *model)
445 {
446 GdaDataPivot *pivot;
447 g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), 0);
448 pivot = GDA_DATA_PIVOT (model);
449 g_return_val_if_fail (pivot->priv, 0);
450
451 if (pivot->priv->columns)
452 return (gint) pivot->priv->columns->len;
453 else
454 return 0;
455 }
456
457 static GdaColumn *
gda_data_pivot_describe_column(GdaDataModel * model,gint col)458 gda_data_pivot_describe_column (GdaDataModel *model, gint col)
459 {
460 GdaDataPivot *pivot;
461 GdaColumn *column = NULL;
462 g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), NULL);
463 pivot = GDA_DATA_PIVOT (model);
464 g_return_val_if_fail (pivot->priv, NULL);
465
466 if (pivot->priv->columns && (col < (gint) pivot->priv->columns->len))
467 column = g_array_index (pivot->priv->columns, GdaColumn*, col);
468 else {
469 if (pivot->priv->columns->len > 0)
470 g_warning ("Column %d out of range (0-%d)", col,
471 (gint) pivot->priv->columns->len);
472 else
473 g_warning ("No column defined");
474 }
475
476 return column;
477 }
478
479 static GdaDataModelAccessFlags
gda_data_pivot_get_access_flags(GdaDataModel * model)480 gda_data_pivot_get_access_flags (GdaDataModel *model)
481 {
482 GdaDataPivot *pivot;
483
484 g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), 0);
485 pivot = GDA_DATA_PIVOT (model);
486 g_return_val_if_fail (pivot->priv, 0);
487
488 return GDA_DATA_MODEL_ACCESS_RANDOM;
489 }
490
491 static const GValue *
gda_data_pivot_get_value_at(GdaDataModel * model,gint col,gint row,GError ** error)492 gda_data_pivot_get_value_at (GdaDataModel *model, gint col, gint row, GError **error)
493 {
494 GdaDataPivot *pivot;
495
496 g_return_val_if_fail (GDA_IS_DATA_PIVOT (model), NULL);
497 pivot = GDA_DATA_PIVOT (model);
498 g_return_val_if_fail (pivot->priv, NULL);
499 g_return_val_if_fail (pivot->priv->model, NULL);
500 g_return_val_if_fail (row >= 0, NULL);
501 g_return_val_if_fail (col >= 0, NULL);
502
503 if (! pivot->priv->results) {
504 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_USAGE_ERROR,
505 "%s", _("Pivot model not populated"));
506 return NULL;
507 }
508 return gda_data_model_get_value_at (pivot->priv->results, col, row, error);
509 }
510
511 static GValue *
aggregate_get_empty_value(GdaDataPivotAggregate aggregate)512 aggregate_get_empty_value (GdaDataPivotAggregate aggregate)
513 {
514 GValue *value;
515 switch (aggregate) {
516 case GDA_DATA_PIVOT_MIN:
517 case GDA_DATA_PIVOT_MAX:
518 case GDA_DATA_PIVOT_AVG:
519 case GDA_DATA_PIVOT_SUM:
520 return gda_value_new_null ();
521 case GDA_DATA_PIVOT_COUNT:
522 value = gda_value_new (G_TYPE_UINT);
523 g_value_set_uint (value, 0);
524 return value;
525 break;
526 default:
527 return gda_value_new_null ();
528 }
529 }
530
531 static gboolean
aggregate_handle_gint(CellData * cdata,gint val)532 aggregate_handle_gint (CellData *cdata, gint val)
533 {
534 if (cdata->data_value) {
535 gint eval = 0;
536 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT)
537 eval = g_value_get_int (cdata->data_value);
538 switch (cdata->aggregate) {
539 case GDA_DATA_PIVOT_MIN:
540 if (eval > val)
541 g_value_set_int (cdata->data_value, val);
542 break;
543 case GDA_DATA_PIVOT_MAX:
544 if (eval < val)
545 g_value_set_int (cdata->data_value, val);
546 break;
547 case GDA_DATA_PIVOT_SUM: {
548 gint64 tmp;
549 tmp = eval + val;
550 if ((tmp > G_MAXINT) || (tmp < G_MININT))
551 g_set_error (&(cdata->error),
552 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
553 "%s", _("Integer overflow"));
554 else
555 g_value_set_int (cdata->data_value, (gint) tmp);
556 break;
557 }
558 case GDA_DATA_PIVOT_AVG: {
559 gint64 tmp;
560 tmp = g_value_get_int64 (cdata->data_value) + val;
561 if ((tmp > G_MAXINT64) || (tmp < G_MININT64))
562 /* FIXME: how to handle overflow detection ? */
563 g_set_error (&(cdata->error),
564 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
565 "%s", _("Integer overflow"));
566 else
567 g_value_set_int64 (cdata->data_value, tmp);
568 break;
569 }
570 default:
571 return FALSE;
572 }
573 }
574 else {
575 /* new initial value */
576 switch (cdata->aggregate) {
577 case GDA_DATA_PIVOT_MIN:
578 case GDA_DATA_PIVOT_MAX:
579 case GDA_DATA_PIVOT_SUM:
580 cdata->data_value = gda_value_new (G_TYPE_INT);
581 g_value_set_int (cdata->data_value, val);
582 break;
583 case GDA_DATA_PIVOT_AVG:
584 cdata->data_value = gda_value_new (G_TYPE_INT64);
585 g_value_set_int64 (cdata->data_value, (gint64) val);
586 break;
587 default:
588 return FALSE;
589 }
590 }
591 cdata->nvalues ++;
592 return TRUE;
593 }
594
595 static gboolean
aggregate_handle_guint(CellData * cdata,guint val)596 aggregate_handle_guint (CellData *cdata, guint val)
597 {
598 if (cdata->data_value) {
599 guint eval = 0;
600 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT)
601 eval = g_value_get_uint (cdata->data_value);
602 switch (cdata->aggregate) {
603 case GDA_DATA_PIVOT_MIN:
604 if (eval > val)
605 g_value_set_uint (cdata->data_value, val);
606 break;
607 case GDA_DATA_PIVOT_MAX:
608 if (eval < val)
609 g_value_set_uint (cdata->data_value, val);
610 break;
611 case GDA_DATA_PIVOT_SUM: {
612 guint64 tmp;
613 tmp = eval + val;
614 if (tmp > G_MAXUINT)
615 g_set_error (&(cdata->error),
616 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
617 "%s", _("Integer overflow"));
618 else
619 g_value_set_uint (cdata->data_value, (guint) tmp);
620 break;
621 }
622 case GDA_DATA_PIVOT_AVG: {
623 guint64 tmp;
624 tmp = g_value_get_uint64 (cdata->data_value) + val;
625 if (tmp > G_MAXUINT64)
626 /* FIXME: how to handle overflow detection ? */
627 g_set_error (&(cdata->error),
628 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
629 "%s", _("Integer overflow"));
630 else
631 g_value_set_uint64 (cdata->data_value, tmp);
632 break;
633 }
634 default:
635 return FALSE;
636 }
637 }
638 else {
639 /* new initial value */
640 switch (cdata->aggregate) {
641 case GDA_DATA_PIVOT_MIN:
642 case GDA_DATA_PIVOT_MAX:
643 case GDA_DATA_PIVOT_SUM:
644 cdata->data_value = gda_value_new (G_TYPE_UINT);
645 g_value_set_uint (cdata->data_value, val);
646 break;
647 case GDA_DATA_PIVOT_AVG:
648 cdata->data_value = gda_value_new (G_TYPE_UINT64);
649 g_value_set_uint64 (cdata->data_value, (guint64) val);
650 break;
651 default:
652 return FALSE;
653 }
654 }
655 cdata->nvalues ++;
656 return TRUE;
657 }
658
659 static gboolean
aggregate_handle_gint64(CellData * cdata,gint64 val)660 aggregate_handle_gint64 (CellData *cdata, gint64 val)
661 {
662 if (cdata->data_value) {
663 gint64 eval = 0;
664 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT64)
665 eval = g_value_get_int64 (cdata->data_value);
666 switch (cdata->aggregate) {
667 case GDA_DATA_PIVOT_MIN:
668 if (eval > val)
669 g_value_set_int64 (cdata->data_value, val);
670 break;
671 case GDA_DATA_PIVOT_MAX:
672 if (eval < val)
673 g_value_set_int64 (cdata->data_value, val);
674 break;
675 case GDA_DATA_PIVOT_SUM:
676 case GDA_DATA_PIVOT_AVG: {
677 gint64 tmp;
678 tmp = eval + val;
679 if ((tmp > G_MAXINT64) || (tmp < G_MININT64))
680 /* FIXME: how to handle overflow detection ? */
681 g_set_error (&(cdata->error),
682 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
683 "%s", _("Integer overflow"));
684 else
685 g_value_set_int64 (cdata->data_value, (gint64) tmp);
686 break;
687 }
688 default:
689 return FALSE;
690 }
691 }
692 else {
693 /* new initial value */
694 switch (cdata->aggregate) {
695 case GDA_DATA_PIVOT_MIN:
696 case GDA_DATA_PIVOT_MAX:
697 case GDA_DATA_PIVOT_SUM:
698 case GDA_DATA_PIVOT_AVG:
699 cdata->data_value = gda_value_new (G_TYPE_INT64);
700 g_value_set_int64 (cdata->data_value, val);
701 break;
702 default:
703 return FALSE;
704 }
705 }
706 cdata->nvalues ++;
707 return TRUE;
708 }
709
710 static gboolean
aggregate_handle_guint64(CellData * cdata,guint val)711 aggregate_handle_guint64 (CellData *cdata, guint val)
712 {
713 if (cdata->data_value) {
714 guint64 eval = 0;
715 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT64)
716 eval = g_value_get_uint64 (cdata->data_value);
717 switch (cdata->aggregate) {
718 case GDA_DATA_PIVOT_MIN:
719 if (eval > val)
720 g_value_set_uint64 (cdata->data_value, val);
721 break;
722 case GDA_DATA_PIVOT_MAX:
723 if (eval < val)
724 g_value_set_uint64 (cdata->data_value, val);
725 break;
726 case GDA_DATA_PIVOT_SUM:
727 case GDA_DATA_PIVOT_AVG: {
728 guint64 tmp;
729 tmp = eval + val;
730 if (tmp > G_MAXUINT64)
731 /* FIXME: how to handle overflow detection ? */
732 g_set_error (&(cdata->error),
733 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
734 "%s", _("Integer overflow"));
735 else
736 g_value_set_uint64 (cdata->data_value, tmp);
737 break;
738 }
739 default:
740 return FALSE;
741 }
742 }
743 else {
744 /* new initial value */
745 switch (cdata->aggregate) {
746 case GDA_DATA_PIVOT_MIN:
747 case GDA_DATA_PIVOT_MAX:
748 case GDA_DATA_PIVOT_SUM:
749 case GDA_DATA_PIVOT_AVG:
750 cdata->data_value = gda_value_new (G_TYPE_UINT64);
751 g_value_set_uint64 (cdata->data_value, val);
752 break;
753 default:
754 return FALSE;
755 }
756 }
757 cdata->nvalues ++;
758 return TRUE;
759 }
760
761 static gboolean
aggregate_handle_float(CellData * cdata,gfloat val)762 aggregate_handle_float (CellData *cdata, gfloat val)
763 {
764 if (cdata->data_value) {
765 gfloat eval = 0;
766 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_FLOAT)
767 eval = g_value_get_float (cdata->data_value);
768 switch (cdata->aggregate) {
769 case GDA_DATA_PIVOT_MIN:
770 if (eval > val)
771 g_value_set_float (cdata->data_value, val);
772 break;
773 case GDA_DATA_PIVOT_MAX:
774 if (eval < val)
775 g_value_set_float (cdata->data_value, val);
776 break;
777 case GDA_DATA_PIVOT_SUM: {
778 gdouble tmp;
779 tmp = eval + val;
780 if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE))
781 g_set_error (&(cdata->error),
782 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
783 "%s", _("Float value overflow"));
784 else
785 g_value_set_float (cdata->data_value, (gfloat) tmp);
786 break;
787 }
788 case GDA_DATA_PIVOT_AVG: {
789 gdouble tmp;
790 tmp = g_value_get_double (cdata->data_value) + val;
791 if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE))
792 g_set_error (&(cdata->error),
793 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
794 "%s", _("Float value overflow"));
795 else
796 g_value_set_double (cdata->data_value, tmp);
797 break;
798 }
799 default:
800 return FALSE;
801 }
802 }
803 else {
804 /* new initial value */
805 switch (cdata->aggregate) {
806 case GDA_DATA_PIVOT_MIN:
807 case GDA_DATA_PIVOT_MAX:
808 case GDA_DATA_PIVOT_SUM:
809 cdata->data_value = gda_value_new (G_TYPE_FLOAT);
810 g_value_set_float (cdata->data_value, val);
811 break;
812 case GDA_DATA_PIVOT_AVG:
813 cdata->data_value = gda_value_new (G_TYPE_DOUBLE);
814 g_value_set_double (cdata->data_value, (gdouble) val);
815 break;
816 default:
817 return FALSE;
818 }
819 }
820 cdata->nvalues ++;
821 return TRUE;
822 }
823
824 static gboolean
aggregate_handle_double(CellData * cdata,gdouble val)825 aggregate_handle_double (CellData *cdata, gdouble val)
826 {
827 if (cdata->data_value) {
828 gdouble eval = 0;
829 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_DOUBLE)
830 eval = g_value_get_double (cdata->data_value);
831 switch (cdata->aggregate) {
832 case GDA_DATA_PIVOT_MIN:
833 if (eval > val)
834 g_value_set_double (cdata->data_value, val);
835 break;
836 case GDA_DATA_PIVOT_MAX:
837 if (eval < val)
838 g_value_set_double (cdata->data_value, val);
839 break;
840 case GDA_DATA_PIVOT_SUM:
841 case GDA_DATA_PIVOT_AVG: {
842 gdouble tmp;
843 tmp = eval + val;
844 if ((tmp > G_MAXDOUBLE) || (tmp < G_MINDOUBLE))
845 /* FIXME: how to handle overflow detection ? */
846 g_set_error (&(cdata->error),
847 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
848 "%s", _("Double value overflow"));
849 else
850 g_value_set_double (cdata->data_value, (gdouble) tmp);
851 break;
852 }
853 default:
854 return FALSE;
855 }
856 }
857 else {
858 /* new initial value */
859 switch (cdata->aggregate) {
860 case GDA_DATA_PIVOT_MIN:
861 case GDA_DATA_PIVOT_MAX:
862 case GDA_DATA_PIVOT_SUM:
863 case GDA_DATA_PIVOT_AVG:
864 cdata->data_value = gda_value_new (G_TYPE_DOUBLE);
865 g_value_set_double (cdata->data_value, val);
866 break;
867 default:
868 return FALSE;
869 }
870 }
871 cdata->nvalues ++;
872 return TRUE;
873 }
874
875 static gboolean
aggregate_handle_char(CellData * cdata,gint8 val)876 aggregate_handle_char (CellData *cdata,
877 gint8 val
878 )
879 {
880 if (cdata->data_value) {
881 gint8 eval = 0;
882 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_CHAR)
883 eval = g_value_get_schar (cdata->data_value);
884 switch (cdata->aggregate) {
885 case GDA_DATA_PIVOT_MIN:
886 if (eval > val)
887 g_value_set_schar (cdata->data_value, val);
888 break;
889 case GDA_DATA_PIVOT_MAX:
890 if (eval < val)
891 g_value_set_schar (cdata->data_value, val);
892 break;
893 case GDA_DATA_PIVOT_SUM: {
894 gint tmp;
895 tmp = eval + val;
896 if ((tmp > G_MAXINT8) || (tmp < G_MININT8))
897 g_set_error (&(cdata->error),
898 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
899 "%s", _("Integer overflow"));
900 else
901 g_value_set_schar (cdata->data_value, (gint8) tmp);
902 break;
903 }
904 case GDA_DATA_PIVOT_AVG: {
905 gint64 tmp;
906 tmp = g_value_get_int64 (cdata->data_value) + val;
907 if ((tmp > G_MAXINT64) || (tmp < G_MININT64))
908 /* FIXME: how to handle overflow detection ? */
909 g_set_error (&(cdata->error),
910 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
911 "%s", _("Integer overflow"));
912 else
913 g_value_set_int64 (cdata->data_value, tmp);
914 break;
915 }
916 default:
917 return FALSE;
918 }
919 }
920 else {
921 /* new initial value */
922 switch (cdata->aggregate) {
923 case GDA_DATA_PIVOT_MIN:
924 case GDA_DATA_PIVOT_MAX:
925 case GDA_DATA_PIVOT_SUM:
926 cdata->data_value = gda_value_new (G_TYPE_CHAR);
927 g_value_set_schar (cdata->data_value, val);
928 break;
929 case GDA_DATA_PIVOT_AVG:
930 cdata->data_value = gda_value_new (G_TYPE_INT64);
931 g_value_set_int64 (cdata->data_value, (gint64) val);
932 break;
933 default:
934 return FALSE;
935 }
936 }
937 cdata->nvalues ++;
938 return TRUE;
939 }
940
941 static gboolean
aggregate_handle_uchar(CellData * cdata,guchar val)942 aggregate_handle_uchar (CellData *cdata, guchar val)
943 {
944 if (cdata->data_value) {
945 guchar eval = 0;
946 if (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UCHAR)
947 eval = g_value_get_uchar (cdata->data_value);
948 switch (cdata->aggregate) {
949 case GDA_DATA_PIVOT_MIN:
950 if (eval > val)
951 g_value_set_uchar (cdata->data_value, val);
952 break;
953 case GDA_DATA_PIVOT_MAX:
954 if (eval < val)
955 g_value_set_uchar (cdata->data_value, val);
956 break;
957 case GDA_DATA_PIVOT_SUM: {
958 guint tmp;
959 tmp = eval + val;
960 if (tmp > G_MAXUINT8)
961 g_set_error (&(cdata->error),
962 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
963 "%s", _("Integer overflow"));
964 else
965 g_value_set_uchar (cdata->data_value, (guchar) tmp);
966 break;
967 }
968 case GDA_DATA_PIVOT_AVG: {
969 guint64 tmp;
970 tmp = g_value_get_uint64 (cdata->data_value) + val;
971 if (tmp > G_MAXUINT64)
972 /* FIXME: how to handle overflow detection ? */
973 g_set_error (&(cdata->error),
974 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
975 "%s", _("Integer overflow"));
976 else
977 g_value_set_uint64 (cdata->data_value, tmp);
978 break;
979 }
980 default:
981 return FALSE;
982 }
983 }
984 else {
985 /* new initial value */
986 switch (cdata->aggregate) {
987 case GDA_DATA_PIVOT_MIN:
988 case GDA_DATA_PIVOT_MAX:
989 case GDA_DATA_PIVOT_SUM:
990 cdata->data_value = gda_value_new (G_TYPE_UCHAR);
991 g_value_set_uchar (cdata->data_value, val);
992 break;
993 case GDA_DATA_PIVOT_AVG:
994 cdata->data_value = gda_value_new (G_TYPE_UINT64);
995 g_value_set_uint64 (cdata->data_value, (guint64) val);
996 break;
997 default:
998 return FALSE;
999 }
1000 }
1001 cdata->nvalues ++;
1002 return TRUE;
1003 }
1004
1005 static gboolean
aggregate_handle_short(CellData * cdata,gshort val)1006 aggregate_handle_short (CellData *cdata, gshort val)
1007 {
1008 if (cdata->data_value) {
1009 gshort eval = 0;
1010 if (G_VALUE_TYPE (cdata->data_value) == GDA_TYPE_SHORT)
1011 eval = gda_value_get_short (cdata->data_value);
1012 switch (cdata->aggregate) {
1013 case GDA_DATA_PIVOT_MIN:
1014 if (eval > val)
1015 gda_value_set_short (cdata->data_value, val);
1016 break;
1017 case GDA_DATA_PIVOT_MAX:
1018 if (eval < val)
1019 gda_value_set_short (cdata->data_value, val);
1020 break;
1021 case GDA_DATA_PIVOT_SUM: {
1022 gint tmp;
1023 tmp = eval + val;
1024 if ((tmp > G_MAXSHORT) || (tmp < G_MINSHORT))
1025 g_set_error (&(cdata->error),
1026 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
1027 "%s", _("Integer overflow"));
1028 else
1029 gda_value_set_short (cdata->data_value, (gshort) tmp);
1030 break;
1031 }
1032 case GDA_DATA_PIVOT_AVG: {
1033 gint64 tmp;
1034 tmp = g_value_get_int64 (cdata->data_value) + val;
1035 if ((tmp > G_MAXINT64) || (tmp < G_MININT64))
1036 /* FIXME: how to handle overflow detection ? */
1037 g_set_error (&(cdata->error),
1038 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
1039 "%s", _("Integer overflow"));
1040 else
1041 g_value_set_int64 (cdata->data_value, tmp);
1042 break;
1043 }
1044 default:
1045 return FALSE;
1046 }
1047 }
1048 else {
1049 /* new initial value */
1050 switch (cdata->aggregate) {
1051 case GDA_DATA_PIVOT_MIN:
1052 case GDA_DATA_PIVOT_MAX:
1053 case GDA_DATA_PIVOT_SUM:
1054 cdata->data_value = gda_value_new (GDA_TYPE_SHORT);
1055 gda_value_set_short (cdata->data_value, val);
1056 break;
1057 case GDA_DATA_PIVOT_AVG:
1058 cdata->data_value = gda_value_new (G_TYPE_INT64);
1059 g_value_set_int64 (cdata->data_value, (gint64) val);
1060 break;
1061 default:
1062 return FALSE;
1063 }
1064 }
1065 cdata->nvalues ++;
1066 return TRUE;
1067 }
1068
1069 static gboolean
aggregate_handle_ushort(CellData * cdata,gushort val)1070 aggregate_handle_ushort (CellData *cdata, gushort val)
1071 {
1072 if (cdata->data_value) {
1073 gushort eval = 0;
1074 if (G_VALUE_TYPE (cdata->data_value) == GDA_TYPE_USHORT)
1075 eval = gda_value_get_ushort (cdata->data_value);
1076 switch (cdata->aggregate) {
1077 case GDA_DATA_PIVOT_MIN:
1078 if (eval > val)
1079 gda_value_set_ushort (cdata->data_value, val);
1080 break;
1081 case GDA_DATA_PIVOT_MAX:
1082 if (eval < val)
1083 gda_value_set_ushort (cdata->data_value, val);
1084 break;
1085 case GDA_DATA_PIVOT_SUM: {
1086 guint tmp;
1087 tmp = eval + val;
1088 if (tmp > G_MAXUSHORT)
1089 g_set_error (&(cdata->error),
1090 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
1091 "%s", _("Integer overflow"));
1092 else
1093 gda_value_set_ushort (cdata->data_value, (gushort) tmp);
1094 break;
1095 }
1096 case GDA_DATA_PIVOT_AVG: {
1097 guint64 tmp;
1098 tmp = g_value_get_uint64 (cdata->data_value) + val;
1099 if (tmp > G_MAXUINT64)
1100 /* FIXME: how to handle overflow detection ? */
1101 g_set_error (&(cdata->error),
1102 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
1103 "%s", _("Integer overflow"));
1104 else
1105 g_value_set_uint64 (cdata->data_value, tmp);
1106 break;
1107 }
1108 default:
1109 return FALSE;
1110 }
1111 }
1112 else {
1113 /* new initial value */
1114 switch (cdata->aggregate) {
1115 case GDA_DATA_PIVOT_MIN:
1116 case GDA_DATA_PIVOT_MAX:
1117 case GDA_DATA_PIVOT_SUM:
1118 cdata->data_value = gda_value_new (GDA_TYPE_USHORT);
1119 gda_value_set_ushort (cdata->data_value, val);
1120 break;
1121 case GDA_DATA_PIVOT_AVG:
1122 cdata->data_value = gda_value_new (G_TYPE_UINT64);
1123 g_value_set_uint64 (cdata->data_value, (guint64) val);
1124 break;
1125 default:
1126 return FALSE;
1127 }
1128 }
1129 cdata->nvalues ++;
1130 return TRUE;
1131 }
1132
1133 /*
1134 * Returns: %TRUE if @new_value_has been handled (even if it created cdata->error),
1135 * or %FALSE if cdata's aggregate needs to store all the data
1136 */
1137 static gboolean
aggregate_handle_new_value(CellData * cdata,const GValue * new_value)1138 aggregate_handle_new_value (CellData *cdata, const GValue *new_value)
1139 {
1140 if (cdata->error)
1141 return TRUE;
1142 else if (cdata->values)
1143 return FALSE;
1144
1145 /* chack data type */
1146 if (G_VALUE_TYPE (new_value) != cdata->gtype) {
1147 if (!cdata->error)
1148 g_set_error (&(cdata->error),
1149 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
1150 "%s", _("Inconsistent data type"));
1151 return TRUE;
1152 }
1153
1154 if (cdata->aggregate == GDA_DATA_PIVOT_COUNT) {
1155 if (cdata->data_value) {
1156 guint64 tmp;
1157 tmp = g_value_get_uint (cdata->data_value) + 1;
1158 if (tmp >= G_MAXUINT)
1159 g_set_error (&(cdata->error),
1160 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_OVERFLOW_ERROR,
1161 "%s", _("Integer overflow"));
1162 else
1163 g_value_set_uint (cdata->data_value, (guint) tmp);
1164 }
1165 else {
1166 cdata->data_value = gda_value_new (G_TYPE_UINT);
1167 g_value_set_uint (cdata->data_value, 1);
1168 }
1169 return TRUE;
1170 }
1171 else if (cdata->gtype == G_TYPE_INT)
1172 return aggregate_handle_gint (cdata, g_value_get_int (new_value));
1173 else if (cdata->gtype == G_TYPE_UINT)
1174 return aggregate_handle_guint (cdata, g_value_get_uint (new_value));
1175 else if (cdata->gtype == G_TYPE_INT64)
1176 return aggregate_handle_gint64 (cdata, g_value_get_int64 (new_value));
1177 else if (cdata->gtype == G_TYPE_UINT64)
1178 return aggregate_handle_guint64 (cdata, g_value_get_uint64 (new_value));
1179 else if (cdata->gtype == G_TYPE_FLOAT)
1180 return aggregate_handle_float (cdata, g_value_get_float (new_value));
1181 else if (cdata->gtype == G_TYPE_DOUBLE)
1182 return aggregate_handle_double (cdata, g_value_get_double (new_value));
1183 else if (cdata->gtype == G_TYPE_CHAR)
1184 return aggregate_handle_char (cdata, g_value_get_schar (new_value));
1185 else if (cdata->gtype == G_TYPE_UCHAR)
1186 return aggregate_handle_uchar (cdata, g_value_get_uchar (new_value));
1187 else if (cdata->gtype == GDA_TYPE_SHORT)
1188 return aggregate_handle_short (cdata, gda_value_get_short (new_value));
1189 else if (cdata->gtype == GDA_TYPE_USHORT)
1190 return aggregate_handle_ushort (cdata, gda_value_get_ushort (new_value));
1191 else {
1192 /* incompatible data type for this kind of operation */
1193 if (!cdata->error)
1194 g_set_error (&(cdata->error),
1195 GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
1196 "%s", _("Data type does not support requested computation"));
1197 return TRUE;
1198 }
1199 }
1200
1201 /*
1202 * Sets cdata->computed_value to a #GValue
1203 * if an error occurs then cdata->computed_value is set to %NULL
1204 *
1205 * Also frees cdata->values.
1206 */
1207 static void
cell_data_compute_aggregate(CellData * cdata)1208 cell_data_compute_aggregate (CellData *cdata)
1209 {
1210 if (cdata->data_value) {
1211 /* finish computation */
1212 if (cdata->error) {
1213 gda_value_free (cdata->data_value);
1214 cdata->data_value = NULL;
1215 }
1216 else if (cdata->aggregate == GDA_DATA_PIVOT_AVG) {
1217 gdouble dval;
1218 if ((cdata->gtype == G_TYPE_INT) || (cdata->gtype == G_TYPE_INT64) ||
1219 (cdata->gtype == G_TYPE_CHAR) || (cdata->gtype == GDA_TYPE_SHORT)) {
1220 gint64 val;
1221 g_assert (G_VALUE_TYPE (cdata->data_value) == G_TYPE_INT64);
1222 val = g_value_get_int64 (cdata->data_value);
1223 dval = val / (gdouble) cdata->nvalues;
1224 }
1225 else if ((cdata->gtype == G_TYPE_UINT) || (cdata->gtype == G_TYPE_UINT64) ||
1226 (cdata->gtype == G_TYPE_UCHAR) || (cdata->gtype == GDA_TYPE_USHORT)) {
1227 guint64 val;
1228 g_assert (G_VALUE_TYPE (cdata->data_value) == G_TYPE_UINT64);
1229 val = g_value_get_uint64 (cdata->data_value);
1230 dval = val / (gdouble) cdata->nvalues;
1231 }
1232 else if (cdata->gtype == G_TYPE_FLOAT)
1233 dval = g_value_get_float (cdata->data_value) / (gdouble) cdata->nvalues;
1234 else if (cdata->gtype == G_TYPE_DOUBLE)
1235 dval = g_value_get_double (cdata->data_value) / (gdouble) cdata->nvalues;
1236 else
1237 g_assert_not_reached ();
1238
1239 gda_value_free (cdata->data_value);
1240 cdata->data_value = gda_value_new (G_TYPE_DOUBLE);
1241 g_value_set_double (cdata->data_value, dval);
1242 }
1243 }
1244 else if (cdata->values) {
1245 TO_IMPLEMENT;
1246 guint i;
1247 for (i = 0; i < cdata->values->len; i++) {
1248 GValue *value;
1249 value = g_array_index (cdata->values, GValue*, i);
1250 gda_value_free (value);
1251 }
1252 g_array_free (cdata->values, TRUE);
1253 cdata->values = NULL;
1254 }
1255 }
1256
1257 static GdaSqlStatement *
parse_field_spec(GdaDataPivot * pivot,const gchar * field,const gchar * alias,GError ** error)1258 parse_field_spec (GdaDataPivot *pivot, const gchar *field, const gchar *alias, GError **error)
1259 {
1260 GdaSqlParser *parser;
1261 gchar *sql;
1262 GdaStatement *stmt;
1263 const gchar *remain;
1264 GError *lerror = NULL;
1265
1266 g_return_val_if_fail (field, FALSE);
1267
1268 if (! bind_source_model (pivot, error))
1269 return NULL;
1270
1271 parser = gda_connection_create_parser (pivot->priv->vcnc);
1272 g_assert (parser);
1273 if (alias && *alias) {
1274 gchar *tmp, *ptr;
1275 tmp = g_strdup (alias);
1276 for (ptr = tmp; *ptr; ptr++) {
1277 if (g_ascii_isdigit (*ptr)) {
1278 if (ptr == tmp)
1279 *ptr = '_';
1280 }
1281 else if (! g_ascii_isalpha (*ptr))
1282 *ptr = '_';
1283 }
1284 sql = g_strdup_printf ("SELECT %s AS %s FROM " TABLE_NAME, field, tmp);
1285 g_free (tmp);
1286 }
1287 else
1288 sql = g_strdup_printf ("SELECT %s FROM " TABLE_NAME, field);
1289 stmt = gda_sql_parser_parse_string (parser, sql, &remain, &lerror);
1290 g_free (sql);
1291 g_object_unref (parser);
1292 if (!stmt || remain) {
1293 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1294 _("Wrong field format error: %s"),
1295 lerror && lerror->message ? lerror->message : _("No detail"));
1296 g_clear_error (&lerror);
1297 return NULL;
1298 }
1299
1300 /* test syntax: a valid SQL expression is required */
1301 GdaSqlStatement *sqlst = NULL;
1302 g_object_get ((GObject*) stmt, "structure", &sqlst, NULL);
1303
1304 if (sqlst->stmt_type != GDA_SQL_STATEMENT_SELECT) {
1305 g_object_unref (stmt);
1306 gda_sql_statement_free (sqlst);
1307 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1308 "%s", _("Wrong field format"));
1309 return NULL;
1310 }
1311
1312 /*
1313 gchar *tmp = gda_sql_statement_serialize (sqlst);
1314 g_print ("SQLST [%p, %s]\n", sqlst, tmp);
1315 g_free (tmp);
1316 */
1317
1318 /* further tests */
1319 GdaDataModel *model;
1320 model = gda_connection_statement_execute_select (pivot->priv->vcnc, stmt, NULL, &lerror);
1321 g_object_unref (stmt);
1322 if (!model) {
1323 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1324 _("Wrong field format error: %s"),
1325 lerror && lerror->message ? lerror->message : _("No detail"));
1326 g_clear_error (&lerror);
1327 return NULL;
1328 }
1329 /*
1330 g_print ("================= Pivot source:\n");
1331 gda_data_model_dump (model, NULL);
1332 */
1333
1334 g_object_unref (model);
1335 return sqlst;
1336 }
1337
1338 /**
1339 * gda_data_pivot_add_field:
1340 * @pivot: a #GdaDataPivot object
1341 * @field_type: the type of field to add
1342 * @field: the field description, see below
1343 * @alias: (allow-none): the field alias, or %NULL
1344 * @error: (allow-none): ta place to store errors, or %NULL
1345 *
1346 * Specifies that @field has to be included in the analysis.
1347 * @field is a field specification with the following accepted syntaxes:
1348 * <itemizedlist>
1349 * <listitem><para>a column name in the source data model (see <link linkend="gda-data-model-get-column-index">gda_data_model_get_column_index()</link>); or</para></listitem>
1350 * <listitem><para>an SQL expression involving a column name in the source data model, for example:
1351 * <programlisting>
1352 * price
1353 * firstname || ' ' || lastname
1354 * nb BETWEEN 5 AND 10</programlisting>
1355 * </para></listitem>
1356 * </itemizedlist>
1357 *
1358 * It is also possible to specify several fields to be added, while separating them by a comma (in effect
1359 * still forming a valid SQL syntax).
1360 *
1361 * Returns: %TRUE if no error occurred
1362 *
1363 * Since: 5.0
1364 */
1365 gboolean
gda_data_pivot_add_field(GdaDataPivot * pivot,GdaDataPivotFieldType field_type,const gchar * field,const gchar * alias,GError ** error)1366 gda_data_pivot_add_field (GdaDataPivot *pivot, GdaDataPivotFieldType field_type,
1367 const gchar *field, const gchar *alias, GError **error)
1368 {
1369 gchar *tmp;
1370 GError *lerror = NULL;
1371
1372 g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE);
1373 g_return_val_if_fail (field, FALSE);
1374
1375 GdaSqlStatement *sqlst;
1376 sqlst = parse_field_spec (pivot, field, alias, error);
1377 if (! sqlst)
1378 return FALSE;
1379
1380 GArray *array;
1381 if (field_type == GDA_DATA_PIVOT_FIELD_ROW) {
1382 if (! pivot->priv->row_fields)
1383 pivot->priv->row_fields = g_array_new (FALSE, FALSE, sizeof (gchar*));
1384 array = pivot->priv->row_fields;
1385 }
1386 else {
1387 if (! pivot->priv->column_fields)
1388 pivot->priv->column_fields = g_array_new (FALSE, FALSE, sizeof (gchar*));
1389 array = pivot->priv->column_fields;
1390 }
1391
1392 GdaSqlStatementSelect *sel;
1393 GSList *sf_list;
1394 sel = (GdaSqlStatementSelect*) sqlst->contents;
1395 for (sf_list = sel->expr_list; sf_list; sf_list = sf_list->next) {
1396 GdaSqlBuilder *b;
1397 GdaSqlBuilderId bid;
1398 GdaSqlSelectField *sf;
1399 sf = (GdaSqlSelectField*) sf_list->data;
1400 b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
1401 gda_sql_builder_select_add_target_id (b,
1402 gda_sql_builder_add_id (b, "T"),
1403 NULL);
1404 bid = gda_sql_builder_import_expression (b, sf->expr);
1405
1406 if (bid == 0) {
1407 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1408 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1409 _("Wrong field format"));
1410 gda_sql_statement_free (sqlst);
1411 return FALSE;
1412 }
1413 gda_sql_builder_add_field_value_id (b, bid, 0);
1414 gchar *sql;
1415 GdaStatement *stmt;
1416 stmt = gda_sql_builder_get_statement (b, &lerror);
1417 g_object_unref (b);
1418 if (!stmt) {
1419 gda_sql_statement_free (sqlst);
1420 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1421 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1422 _("Wrong field format error: %s"),
1423 lerror && lerror->message ? lerror->message : _("No detail"));
1424 g_clear_error (&lerror);
1425 return FALSE;
1426 }
1427 sql = gda_statement_to_sql (stmt, NULL, NULL);
1428 g_object_unref (stmt);
1429 if (!sql) {
1430 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1431 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1432 _("Wrong field format"));
1433 gda_sql_statement_free (sqlst);
1434 return FALSE;
1435 }
1436 /*g_print ("PART [%s][%s]\n", sql, sf->as);*/
1437 tmp = sql + 7; /* remove the "SELECT " start */
1438 tmp [strlen (tmp) - 7] = 0; /* remove the " FROM T" end */
1439 if (sf->as && *(sf->as)) {
1440 gchar *tmp2;
1441 tmp2 = g_strdup_printf ("%s AS %s", tmp, sf->as);
1442 g_array_append_val (array, tmp2);
1443 }
1444 else {
1445 tmp = g_strdup (tmp);
1446 g_array_append_val (array, tmp);
1447 }
1448 g_free (sql);
1449 }
1450
1451 gda_sql_statement_free (sqlst);
1452
1453 clean_previous_population (pivot);
1454
1455 return TRUE;
1456 }
1457
1458 /**
1459 * gda_data_pivot_add_data:
1460 * @pivot: a #GdaDataPivot object
1461 * @aggregate_type: the type of aggregate operation to perform
1462 * @field: the field description, see below
1463 * @alias: (allow-none): the field alias, or %NULL
1464 * @error: (allow-none): ta place to store errors, or %NULL
1465 *
1466 * Specifies that @field has to be included in the analysis.
1467 * @field is a field specification with the following accepted syntaxes:
1468 * <itemizedlist>
1469 * <listitem><para>a column name in the source data model (see <link linkend="gda-data-model-get-column-index">gda_data_model_get_column_index()</link>); or</para></listitem>
1470 * <listitem><para>an SQL expression involving a column name in the source data model, for examples:
1471 * <programlisting>
1472 * price
1473 * firstname || ' ' || lastname
1474 * nb BETWEEN 5 AND 10</programlisting>
1475 * </para></listitem>
1476 * </itemizedlist>
1477 *
1478 * It is also possible to specify several fields to be added, while separating them by a comma (in effect
1479 * still forming a valid SQL syntax).
1480 *
1481 * Returns: %TRUE if no error occurred
1482 *
1483 * Since: 5.0
1484 */
1485 gboolean
gda_data_pivot_add_data(GdaDataPivot * pivot,GdaDataPivotAggregate aggregate_type,const gchar * field,const gchar * alias,GError ** error)1486 gda_data_pivot_add_data (GdaDataPivot *pivot, GdaDataPivotAggregate aggregate_type,
1487 const gchar *field, const gchar *alias, GError **error)
1488 {
1489 gchar *tmp;
1490 GError *lerror = NULL;
1491
1492 g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE);
1493 g_return_val_if_fail (field, FALSE);
1494
1495 GdaSqlStatement *sqlst;
1496 sqlst = parse_field_spec (pivot, field, alias, error);
1497 if (! sqlst)
1498 return FALSE;
1499
1500 if (! pivot->priv->data_fields)
1501 pivot->priv->data_fields = g_array_new (FALSE, FALSE, sizeof (gchar*));
1502 if (! pivot->priv->data_aggregates)
1503 pivot->priv->data_aggregates = g_array_new (FALSE, FALSE, sizeof (GdaDataPivotAggregate));
1504
1505 GdaSqlStatementSelect *sel;
1506 GSList *sf_list;
1507 sel = (GdaSqlStatementSelect*) sqlst->contents;
1508 for (sf_list = sel->expr_list; sf_list; sf_list = sf_list->next) {
1509 GdaSqlBuilder *b;
1510 GdaSqlBuilderId bid;
1511 GdaSqlSelectField *sf;
1512 sf = (GdaSqlSelectField*) sf_list->data;
1513 b = gda_sql_builder_new (GDA_SQL_STATEMENT_SELECT);
1514 gda_sql_builder_select_add_target_id (b,
1515 gda_sql_builder_add_id (b, "T"),
1516 NULL);
1517 bid = gda_sql_builder_import_expression (b, sf->expr);
1518
1519 if (bid == 0) {
1520 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1521 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1522 _("Wrong field format"));
1523 gda_sql_statement_free (sqlst);
1524 return FALSE;
1525 }
1526 gda_sql_builder_add_field_value_id (b, bid, 0);
1527 gchar *sql;
1528 GdaStatement *stmt;
1529 stmt = gda_sql_builder_get_statement (b, &lerror);
1530 g_object_unref (b);
1531 if (!stmt) {
1532 gda_sql_statement_free (sqlst);
1533 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1534 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1535 _("Wrong field format error: %s"),
1536 lerror && lerror->message ? lerror->message : _("No detail"));
1537 g_clear_error (&lerror);
1538 return FALSE;
1539 }
1540 sql = gda_statement_to_sql (stmt, NULL, NULL);
1541 g_object_unref (stmt);
1542 if (!sql) {
1543 g_set_error (error, GDA_DATA_PIVOT_ERROR,
1544 GDA_DATA_PIVOT_FIELD_FORMAT_ERROR,
1545 _("Wrong field format"));
1546 gda_sql_statement_free (sqlst);
1547 return FALSE;
1548 }
1549 /*g_print ("PART [%s][%s]\n", sql, sf->as);*/
1550 tmp = sql + 7; /* remove the "SELECT " start */
1551 tmp [strlen (tmp) - 7] = 0; /* remove the " FROM T" end */
1552 if (sf->as && *(sf->as)) {
1553 gchar *tmp2;
1554 tmp2 = g_strdup_printf ("%s AS %s", tmp, sf->as);
1555 g_array_append_val (pivot->priv->data_fields, tmp2);
1556 }
1557 else {
1558 tmp = g_strdup (tmp);
1559 g_array_append_val (pivot->priv->data_fields, tmp);
1560 }
1561 g_array_append_val (pivot->priv->data_aggregates, aggregate_type);
1562 g_free (sql);
1563 }
1564
1565 gda_sql_statement_free (sqlst);
1566
1567 clean_previous_population (pivot);
1568
1569 return TRUE;
1570 }
1571
1572 /**
1573 * gda_data_pivot_populate:
1574 * @pivot: a #GdaDataPivot object
1575 * @error: (allow-none): ta place to store errors, or %NULL
1576 *
1577 * Acutally populates @pivot by analysing the data from the provided data model.
1578 *
1579 * Returns: %TRUE if no error occurred.
1580 *
1581 * Since: 5.0
1582 */
1583 gboolean
gda_data_pivot_populate(GdaDataPivot * pivot,GError ** error)1584 gda_data_pivot_populate (GdaDataPivot *pivot, GError **error)
1585 {
1586 gboolean retval = FALSE;
1587 g_return_val_if_fail (GDA_IS_DATA_PIVOT (pivot), FALSE);
1588
1589 if (!pivot->priv->row_fields || (pivot->priv->row_fields->len == 0)) {
1590 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_USAGE_ERROR,
1591 "%s", _("No row field defined"));
1592 return FALSE;
1593 }
1594
1595 clean_previous_population (pivot);
1596
1597 /*
1598 * create data model extracted using the virtual connection.
1599 * The resulting data model's columns are:
1600 * - for pivot->priv->row_fields: 0 to pivot->priv->row_fields->len - 1
1601 * - for pivot->priv->column_fields:
1602 * pivot->priv->row_fields->len to pivot->priv->row_fields->len + pivot->priv->column_fields->len - 1
1603 * - for pivot->priv->data_fields: pivot->priv->row_fields->len + pivot->priv->column_fields->len to pivot->priv->row_fields->len + pivot->priv->column_fields->len + pivot->priv->data_fields->len - 1
1604 */
1605 GString *string;
1606 guint i;
1607 string = g_string_new ("SELECT ");
1608 for (i = 0; i < pivot->priv->row_fields->len; i++) {
1609 gchar *part;
1610 part = g_array_index (pivot->priv->row_fields, gchar *, i);
1611 if (i != 0)
1612 g_string_append (string, ", ");
1613 g_string_append (string, part);
1614 }
1615 if (pivot->priv->column_fields) {
1616 for (i = 0; i < pivot->priv->column_fields->len; i++) {
1617 gchar *part;
1618 part = g_array_index (pivot->priv->column_fields, gchar *, i);
1619 g_string_append (string, ", ");
1620 g_string_append (string, part);
1621 }
1622 }
1623 if (pivot->priv->data_fields) {
1624 for (i = 0; i < pivot->priv->data_fields->len; i++) {
1625 gchar *part;
1626 part = g_array_index (pivot->priv->data_fields, gchar *, i);
1627 g_string_append (string, ", ");
1628 g_string_append (string, part);
1629 }
1630 }
1631 g_string_append (string, " FROM " TABLE_NAME);
1632
1633 GdaStatement *stmt;
1634 stmt = gda_connection_parse_sql_string (pivot->priv->vcnc, string->str, NULL, NULL);
1635 g_string_free (string, TRUE);
1636 if (!stmt) {
1637 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
1638 "%s", _("Could not get information from source data model"));
1639 return FALSE;
1640 }
1641
1642 GdaDataModel *model;
1643 model = gda_connection_statement_execute_select_full (pivot->priv->vcnc, stmt, NULL,
1644 GDA_STATEMENT_MODEL_CURSOR_FORWARD,
1645 //GDA_STATEMENT_MODEL_RANDOM_ACCESS,
1646 NULL, NULL);
1647 g_object_unref (stmt);
1648 if (!model) {
1649 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
1650 "%s", _("Could not get information from source data model"));
1651 return FALSE;
1652 }
1653
1654 /*
1655 g_print ("========== Iterable data model\n");
1656 gda_data_model_dump (model, NULL);
1657 */
1658
1659 /* iterate through the data model */
1660 GdaDataModelIter *iter;
1661 gint col;
1662 iter = gda_data_model_create_iter (model);
1663 if (!iter) {
1664 g_object_unref (model);
1665 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
1666 "%s", _("Could not get information from source data model"));
1667 return FALSE;
1668 }
1669
1670 pivot->priv->columns = g_array_new (FALSE, FALSE, sizeof (GdaColumn*));
1671 for (col = 0; col < (gint) pivot->priv->row_fields->len; col++) {
1672 GdaColumn *column;
1673 GdaHolder *holder;
1674 column = gda_column_new ();
1675 holder = GDA_HOLDER (g_slist_nth_data (GDA_SET (iter)->holders, col));
1676
1677 gda_column_set_name (column, gda_holder_get_id (holder));
1678 gda_column_set_description (column, gda_holder_get_id (holder));
1679 gda_column_set_g_type (column, gda_holder_get_g_type (holder));
1680 gda_column_set_position (column, col);
1681 g_array_append_val (pivot->priv->columns, column);
1682 }
1683
1684 /*
1685 * actual computation
1686 */
1687 GHashTable *column_values_index; /* key = a #GValue (ref held in @column_values),
1688 * value = pointer to a guint containing the position
1689 * in @columns of the column */
1690
1691 GArray *first_rows; /* Array of GdaRow objects, the size of each GdaRow is
1692 * the number of row fields defined */
1693 GHashTable *first_rows_index; /* key = a #GdaRow (ref held in @first_rows),
1694 * value = pointer to a guint containing the position
1695 * in @first_rows of the row. */
1696 GHashTable *data_hash; /* key = a CellData pointer, value = The CellData pointer
1697 * as ref'ed in @data */
1698
1699 first_rows = g_array_new (FALSE, FALSE, sizeof (GdaRow*));
1700 first_rows_index = g_hash_table_new_full (_gda_row_hash, _gda_row_equal, NULL, g_free);
1701 column_values_index = g_hash_table_new_full (column_data_hash, column_data_equal,
1702 (GDestroyNotify) column_data_free, g_free);
1703 data_hash = g_hash_table_new_full (cell_data_hash, cell_data_equal,
1704 (GDestroyNotify) cell_data_free, NULL);
1705
1706 for (;gda_data_model_iter_move_next (iter);) {
1707 /*
1708 * Row handling
1709 */
1710 GdaRow *nrow;
1711 #ifdef GDA_DEBUG_ROWS_HASH
1712 g_print ("read from iter: ");
1713 #endif
1714 nrow = gda_row_new ((gint) pivot->priv->row_fields->len);
1715 for (col = 0; col < (gint) pivot->priv->row_fields->len; col++) {
1716 const GValue *ivalue;
1717 GValue *rvalue;
1718 GError *lerror = NULL;
1719 ivalue = gda_data_model_iter_get_value_at_e (iter, col, &lerror);
1720 if (!ivalue || lerror) {
1721 clean_previous_population (pivot);
1722 g_object_unref (nrow);
1723 g_propagate_error (error, lerror);
1724 goto out;
1725 }
1726 rvalue = gda_row_get_value (nrow, col);
1727 gda_value_reset_with_type (rvalue, G_VALUE_TYPE (ivalue));
1728 g_value_copy (ivalue, rvalue);
1729 #ifdef GDA_DEBUG_ROWS_HASH
1730 gchar *tmp;
1731 tmp = gda_value_stringify (rvalue);
1732 g_print ("[%s]", tmp);
1733 g_free (tmp);
1734 #endif
1735 }
1736
1737 gint *rowindex; /* *rowindex will contain the actual row of the resulting data mode */
1738 rowindex = g_hash_table_lookup (first_rows_index, nrow);
1739 if (rowindex)
1740 g_object_unref (nrow);
1741 else {
1742 g_array_append_val (first_rows, nrow);
1743 rowindex = g_new (gint, 1);
1744 *rowindex = first_rows->len - 1;
1745 g_hash_table_insert (first_rows_index, nrow,
1746 rowindex);
1747 }
1748 #ifdef GDA_DEBUG_ROWS_HASH
1749 g_print (" => @row %d\n", *rowindex);
1750 #endif
1751
1752 /*
1753 * Column handling
1754 */
1755 gint colsmax;
1756 if (pivot->priv->column_fields)
1757 colsmax = (gint) pivot->priv->column_fields->len;
1758 else
1759 colsmax = 1;
1760 for (col = 0; col < colsmax; col++) {
1761 const GValue *ivalue = NULL;
1762 GError *lerror = NULL;
1763 if (pivot->priv->column_fields) {
1764 ivalue = gda_data_model_iter_get_value_at_e (iter,
1765 col + pivot->priv->row_fields->len,
1766 &lerror);
1767 if (!ivalue || lerror) {
1768 clean_previous_population (pivot);
1769 g_propagate_error (error, lerror);
1770 goto out;
1771 }
1772 }
1773
1774 gint di, dimax;
1775 if (pivot->priv->data_fields && pivot->priv->data_fields->len > 0) {
1776 di = 0;
1777 dimax = pivot->priv->data_fields->len;
1778 }
1779 else {
1780 di = -1;
1781 dimax = 0;
1782 }
1783 for (; di < dimax; di++) {
1784 ColumnData coldata;
1785 gint *colindex;
1786 GdaDataPivotAggregate aggregate;
1787 coldata.value = (GValue*) ivalue;
1788 coldata.column_fields_index = col;
1789 coldata.data_pos = di;
1790 colindex = g_hash_table_lookup (column_values_index, &coldata);
1791 if (di >= 0)
1792 aggregate = g_array_index (pivot->priv->data_aggregates,
1793 GdaDataPivotAggregate, di);
1794 else
1795 aggregate = GDA_DATA_PIVOT_SUM;
1796
1797 if (!colindex) {
1798 /* create new column */
1799 GdaColumn *column;
1800 GString *name;
1801
1802 name = g_string_new ("");
1803 if (pivot->priv->column_fields &&
1804 pivot->priv->column_fields->len > 1) {
1805 GdaColumn *column;
1806 column = gda_data_model_describe_column (model,
1807 pivot->priv->row_fields->len + col);
1808 g_string_append_printf (name, "[%s]",
1809 gda_column_get_name (column));
1810 }
1811 if (ivalue) {
1812 gchar *tmp;
1813 tmp = gda_value_stringify (ivalue);
1814 g_string_append (name, tmp);
1815 g_free (tmp);
1816 }
1817 if ((di >= 0) && (dimax > 0)) {
1818 GdaColumn *column;
1819 gint vcol;
1820 vcol = pivot->priv->row_fields->len + di;
1821 if (pivot->priv->column_fields)
1822 vcol += pivot->priv->column_fields->len;
1823 column = gda_data_model_describe_column (model, vcol);
1824 if (pivot->priv->column_fields)
1825 g_string_append_printf (name, "[%s]",
1826 gda_column_get_name (column));
1827 else
1828 g_string_append (name,
1829 gda_column_get_name (column));
1830 }
1831
1832 column = gda_column_new ();
1833 g_object_set_data ((GObject*) column, "agg",
1834 GINT_TO_POINTER (aggregate));
1835 gda_column_set_name (column, name->str);
1836 gda_column_set_description (column, name->str);
1837 g_array_append_val (pivot->priv->columns, column);
1838 gda_column_set_position (column, pivot->priv->columns->len - 1);
1839 /* don't set the column's type now */
1840 /*g_print ("New column [%s] @real column %d, type %s\n", name->str, pivot->priv->columns->len - 1, gda_g_type_to_string (gda_column_get_g_type (column)));*/
1841 g_string_free (name, TRUE);
1842
1843 ColumnData *ncoldata;
1844 ncoldata = g_new (ColumnData, 1);
1845 ncoldata->value = ivalue ? gda_value_copy ((GValue*) ivalue) : NULL;
1846 ncoldata->column_fields_index = col;
1847 ncoldata->data_pos = di;
1848 colindex = g_new (gint, 1);
1849 *colindex = pivot->priv->columns->len - 1;
1850 g_hash_table_insert (column_values_index, ncoldata,
1851 colindex);
1852 }
1853
1854 /* compute value to take into account */
1855 GValue *value = NULL;
1856 if (di >= 0) {
1857 const GValue *cvalue;
1858 GError *lerror = NULL;
1859 gint vcol;
1860 vcol = pivot->priv->row_fields->len + di;
1861 if (pivot->priv->column_fields)
1862 vcol += pivot->priv->column_fields->len;
1863 cvalue = gda_data_model_iter_get_value_at_e (iter, vcol, &lerror);
1864 if (!cvalue || lerror) {
1865 g_propagate_error (error, lerror);
1866 goto out;
1867 }
1868 if (G_VALUE_TYPE (cvalue) != GDA_TYPE_NULL)
1869 value = gda_value_copy (cvalue);
1870 }
1871 else {
1872 value = gda_value_new (G_TYPE_INT);
1873 g_value_set_int (value, 1);
1874 }
1875
1876 if (value) {
1877 /* accumulate data */
1878 CellData ccdata, *pcdata;
1879 ccdata.row = *rowindex;
1880 ccdata.col = *colindex;
1881 ccdata.values = NULL;
1882 ccdata.data_value = NULL;
1883 pcdata = g_hash_table_lookup (data_hash, &ccdata);
1884 if (!pcdata) {
1885 pcdata = g_new (CellData, 1);
1886 pcdata->row = *rowindex;
1887 pcdata->col = *colindex;
1888 pcdata->error = NULL;
1889 pcdata->values = NULL;
1890 pcdata->gtype = G_VALUE_TYPE (value);
1891 pcdata->nvalues = 0;
1892 pcdata->data_value = NULL;
1893 pcdata->aggregate = aggregate;
1894 g_hash_table_insert (data_hash, pcdata, pcdata);
1895 }
1896 if (!aggregate_handle_new_value (pcdata, value)) {
1897 if (!pcdata->values)
1898 pcdata->values = g_array_new (FALSE, FALSE,
1899 sizeof (GValue*));
1900 g_array_append_val (pcdata->values, value);
1901 }
1902 /*g_print ("row %d col %d => [%s]\n", pcdata->row, pcdata->col,
1903 gda_value_stringify (value));*/
1904 }
1905 }
1906 }
1907 }
1908 if (gda_data_model_iter_get_row (iter) != -1) {
1909 /* an error occurred! */
1910 goto out;
1911 }
1912
1913 /* compute real data model's values from all the collected data */
1914 GdaDataModel *results;
1915 gint ncols, nrows;
1916 ncols = pivot->priv->columns->len;
1917 nrows = first_rows->len;
1918 results = gda_data_model_array_new (ncols);
1919 for (i = 0; i < pivot->priv->row_fields->len; i++) {
1920 GdaColumn *acolumn, *ecolumn;
1921 ecolumn = g_array_index (pivot->priv->columns, GdaColumn*, i);
1922 acolumn = gda_data_model_describe_column (results, i);
1923 gda_column_set_g_type (acolumn, gda_column_get_g_type (ecolumn));
1924
1925 gint j;
1926 for (j = 0; j < nrows; j++) {
1927 GdaRow *arow, *erow;
1928 erow = g_array_index (first_rows, GdaRow*, j);
1929 arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j, NULL);
1930 if (!arow) {
1931 g_assert (gda_data_model_append_row (results, NULL) == j);
1932 arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j,
1933 NULL);
1934 g_assert (arow);
1935 }
1936 GValue *av, *ev;
1937 av = gda_row_get_value (arow, i);
1938 ev = gda_row_get_value (erow, i);
1939 gda_value_reset_with_type (av, G_VALUE_TYPE (ev));
1940 g_value_copy (ev, av);
1941 }
1942 }
1943 for (; i < (guint) ncols; i++) {
1944 GdaColumn *ecolumn;
1945 ecolumn = g_array_index (pivot->priv->columns, GdaColumn*, i);
1946
1947 gint j;
1948 for (j = 0; j < nrows; j++) {
1949 GdaRow *arow;
1950 GValue *av;
1951 arow = gda_data_model_array_get_row ((GdaDataModelArray*) results, j, NULL);
1952 av = gda_row_get_value (arow, i);
1953
1954 CellData ccdata, *pcdata;
1955 GType coltype = GDA_TYPE_NULL;
1956 ccdata.row = j;
1957 ccdata.col = i;
1958 ccdata.values = NULL;
1959 ccdata.data_value = NULL;
1960 pcdata = g_hash_table_lookup (data_hash, &ccdata);
1961 if (pcdata) {
1962 cell_data_compute_aggregate (pcdata);
1963 if (pcdata->data_value) {
1964 coltype = G_VALUE_TYPE (pcdata->data_value);
1965 gda_value_reset_with_type (av, coltype);
1966 g_value_copy (pcdata->data_value, av);
1967 }
1968 else
1969 gda_row_invalidate_value (arow, av);
1970 }
1971 else {
1972 GValue *empty;
1973 GdaDataPivotAggregate agg;
1974 agg = GPOINTER_TO_INT (g_object_get_data ((GObject*) ecolumn, "agg"));
1975 empty = aggregate_get_empty_value (agg);
1976 coltype = G_VALUE_TYPE (empty);
1977 gda_value_reset_with_type (av, coltype);
1978 g_value_copy (empty, av);
1979 }
1980 if (coltype != GDA_TYPE_NULL)
1981 gda_column_set_g_type (ecolumn, coltype);
1982 }
1983 }
1984 pivot->priv->results = results;
1985
1986 retval = TRUE;
1987
1988 out:
1989 if (!retval)
1990 clean_previous_population (pivot);
1991
1992 if (data_hash)
1993 g_hash_table_destroy (data_hash);
1994
1995 if (first_rows) {
1996 guint i;
1997 for (i = 0; i < first_rows->len; i++) {
1998 GObject *obj;
1999 obj = g_array_index (first_rows, GObject*, i);
2000 if (obj)
2001 g_object_unref (obj);
2002 }
2003 g_array_free (first_rows, TRUE);
2004 }
2005
2006 if (first_rows_index)
2007 g_hash_table_destroy (first_rows_index);
2008
2009 g_hash_table_destroy (column_values_index);
2010
2011 g_object_unref (iter);
2012 g_object_unref (model);
2013
2014 return retval;
2015 }
2016
2017 static guint
_gda_value_hash(gconstpointer key)2018 _gda_value_hash (gconstpointer key)
2019 {
2020 GValue *v;
2021 GType vt;
2022 guint res = 0;
2023 v = (GValue *) key;
2024 vt = G_VALUE_TYPE (v);
2025 if ((vt == G_TYPE_BOOLEAN) || (vt == G_TYPE_INT) || (vt == G_TYPE_UINT) ||
2026 (vt == G_TYPE_FLOAT) || (vt == G_TYPE_DOUBLE) ||
2027 (vt == G_TYPE_INT64) || (vt == G_TYPE_INT64) ||
2028 (vt == GDA_TYPE_SHORT) || (vt == GDA_TYPE_USHORT) ||
2029 (vt == G_TYPE_CHAR) || (vt == G_TYPE_UCHAR) ||
2030 (vt == GDA_TYPE_NULL) || (vt == G_TYPE_GTYPE) ||
2031 (vt == G_TYPE_LONG) || (vt == G_TYPE_ULONG)) {
2032 const signed char *p, *data;
2033 data = (signed char*) v;
2034 res = 5381;
2035 for (p = data; p < data + sizeof (GValue); p++)
2036 res = (res << 5) + res + *p;
2037 }
2038 else if (vt == G_TYPE_STRING) {
2039 const gchar *tmp;
2040 tmp = g_value_get_string (v);
2041 if (tmp)
2042 res += g_str_hash (tmp);
2043 }
2044 else if ((vt == GDA_TYPE_BINARY) || (vt == GDA_TYPE_BLOB)) {
2045 const GdaBinary *bin;
2046 if (vt == GDA_TYPE_BLOB) {
2047 GdaBlob *blob;
2048 blob = (GdaBlob*) gda_value_get_blob ((GValue *) v);
2049 bin = (GdaBinary *) blob;
2050 if (blob->op &&
2051 (bin->binary_length != gda_blob_op_get_length (blob->op)))
2052 gda_blob_op_read_all (blob->op, blob);
2053 }
2054 else
2055 bin = gda_value_get_binary ((GValue *) v);
2056 if (bin) {
2057 glong l;
2058 for (l = 0; l < bin->binary_length; l++)
2059 res += (guint) bin->data [l];
2060 }
2061 }
2062 else {
2063 gchar *tmp;
2064 tmp = gda_value_stringify (v);
2065 res += g_str_hash (tmp);
2066 g_free (tmp);
2067 }
2068 return res;
2069 }
2070
2071 static guint
_gda_row_hash(gconstpointer key)2072 _gda_row_hash (gconstpointer key)
2073 {
2074 gint i, len;
2075 GdaRow *r;
2076 guint res = 0;
2077 r = (GdaRow*) key;
2078 len = gda_row_get_length (r);
2079 for (i = 0; i < len ; i++) {
2080 GValue *v;
2081 v = gda_row_get_value (r, i);
2082 res = (res << 5) + res + _gda_value_hash (v);
2083 }
2084 return res;
2085 }
2086
2087 static gboolean
_gda_row_equal(gconstpointer a,gconstpointer b)2088 _gda_row_equal (gconstpointer a, gconstpointer b)
2089 {
2090 gint i, len;
2091 GdaRow *ra, *rb;
2092 ra = (GdaRow*) a;
2093 rb = (GdaRow*) b;
2094 len = gda_row_get_length (ra);
2095 g_assert (len == gda_row_get_length (rb));
2096 for (i = 0; i < len ; i++) {
2097 GValue *va, *vb;
2098 va = gda_row_get_value (ra, i);
2099 vb = gda_row_get_value (rb, i);
2100 if (gda_value_differ (va, vb))
2101 return FALSE;
2102 }
2103 return TRUE;
2104 }
2105
2106 /*
2107 * Create a new virtual connection for @pivot
2108 */
2109 static gboolean
create_vcnc(GdaDataPivot * pivot,GError ** error)2110 create_vcnc (GdaDataPivot *pivot, GError **error)
2111 {
2112 GdaConnection *vcnc;
2113 GError *lerror = NULL;
2114 if (!pivot->priv->vcnc && GDA_IS_CONNECTION (pivot->priv->vcnc))
2115 return TRUE;
2116
2117 g_rec_mutex_lock (&pivot->priv->provider_mutex);
2118 if (!pivot->priv->virtual_provider)
2119 pivot->priv->virtual_provider = gda_vprovider_data_model_new ();
2120
2121 vcnc = gda_virtual_connection_open (pivot->priv->virtual_provider, &lerror);
2122 if (! vcnc) {
2123 g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
2124 if (lerror)
2125 g_error_free (lerror);
2126 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_INTERNAL_ERROR,
2127 "%s", _("Could not create virtual connection"));
2128 return FALSE;
2129 }
2130
2131 pivot->priv->vcnc = vcnc;
2132 g_rec_mutex_unlock (&pivot->priv->provider_mutex);
2133 return TRUE;
2134 }
2135
2136 /*
2137 * Bind @pivot->priv->model as a table named TABLE_NAME in @pivot's virtual connection
2138 */
2139 static gboolean
bind_source_model(GdaDataPivot * pivot,GError ** error)2140 bind_source_model (GdaDataPivot *pivot, GError **error)
2141 {
2142 if (! pivot->priv->model) {
2143 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_SOURCE_MODEL_ERROR,
2144 "%s", _("No source defined"));
2145 return FALSE;
2146 }
2147 if (! create_vcnc (pivot, error))
2148 return FALSE;
2149
2150 if (gda_vconnection_data_model_get_model (GDA_VCONNECTION_DATA_MODEL (pivot->priv->vcnc),
2151 TABLE_NAME) == pivot->priv->model) {
2152 /* already bound */
2153 return TRUE;
2154 }
2155
2156 if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (pivot->priv->vcnc),
2157 pivot->priv->model,
2158 TABLE_NAME, NULL)) {
2159 g_set_error (error, GDA_DATA_PIVOT_ERROR, GDA_DATA_PIVOT_SOURCE_MODEL_ERROR,
2160 "%s",
2161 _("Invalid source data model (may have incompatible column names)"));
2162 return FALSE;
2163 }
2164
2165 return TRUE;
2166 }
2167
2168 static
column_data_hash(gconstpointer key)2169 guint column_data_hash (gconstpointer key)
2170 {
2171 ColumnData *cd;
2172 cd = (ColumnData*) key;
2173 if (cd->value)
2174 return _gda_value_hash (cd->value) + cd->column_fields_index + cd->data_pos;
2175 else
2176 return cd->column_fields_index + cd->data_pos;
2177 }
2178
2179 static gboolean
column_data_equal(gconstpointer a,gconstpointer b)2180 column_data_equal (gconstpointer a, gconstpointer b)
2181 {
2182 ColumnData *cda, *cdb;
2183 cda = (ColumnData*) a;
2184 cdb = (ColumnData*) b;
2185 if ((cda->column_fields_index != cdb->column_fields_index) ||
2186 (cda->data_pos != cdb->data_pos))
2187 return FALSE;
2188 if (cda->value && cdb->value)
2189 return gda_value_differ (cda->value, cdb->value) ? FALSE : TRUE;
2190 else if (cda->value || cdb->value)
2191 return FALSE;
2192 else
2193 return TRUE;
2194 }
2195
2196 static void
column_data_free(ColumnData * cdata)2197 column_data_free (ColumnData *cdata)
2198 {
2199 gda_value_free (cdata->value);
2200 g_free (cdata);
2201 }
2202
2203 static guint
cell_data_hash(gconstpointer key)2204 cell_data_hash (gconstpointer key)
2205 {
2206 CellData *cd;
2207 cd = (CellData*) key;
2208 return g_int_hash (&(cd->row)) + g_int_hash (&(cd->col));
2209 }
2210
2211 static gboolean
cell_data_equal(gconstpointer a,gconstpointer b)2212 cell_data_equal (gconstpointer a, gconstpointer b)
2213 {
2214 CellData *cda, *cdb;
2215 cda = (CellData*) a;
2216 cdb = (CellData*) b;
2217 if ((cda->row == cdb->row) && (cda->col == cdb->col))
2218 return TRUE;
2219 else
2220 return FALSE;
2221 }
2222
2223 static void
cell_data_free(CellData * cdata)2224 cell_data_free (CellData *cdata)
2225 {
2226 if (cdata->values) {
2227 guint i;
2228 for (i = 0; i < cdata->values->len; i++) {
2229 GValue *value;
2230 value = g_array_index (cdata->values, GValue*, i);
2231 gda_value_free (value);
2232 }
2233 g_array_free (cdata->values, TRUE);
2234 }
2235 gda_value_free (cdata->data_value);
2236 g_free (cdata);
2237 }
2238