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 (&registering);
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 (&registering);
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