1 /*
2  * Copyright (C) 2007 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2008 Murray Cumming <murrayc@murrayc.com>
4  * Copyright (C) 2010 David King <davidk@openismus.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301, USA.
20  */
21 
22 #include <libxml/xpathInternals.h>
23 #include <libxslt/variables.h>
24 
25 #include <libgda/libgda.h>
26 
27 #include "libgda-xslt.h"
28 #include "sql_backend.h"
29 #include <libxml/xpathInternals.h>
30 #include <libgda/gda-debug-macros.h>
31 
32 #include <libgda/handlers/gda-handler-boolean.h>
33 #include <libgda/handlers/gda-handler-numerical.h>
34 #include <libgda/handlers/gda-handler-string.h>
35 #include <libgda/handlers/gda-handler-time.h>
36 #include <libgda/handlers/gda-handler-type.h>
37 
38 #include <sql-parser/gda-sql-parser.h>
39 
40 static GHashTable *data_handlers = NULL;	/* key = GType, value = GdaDataHandler obj */
41 static xmlChar *value_to_xmlchar (const GValue * value);
42 
43 
44 
45 static void look_predefined_query_by_name (GdaXsltExCont * exec,
46 					   const char *query_name,
47 					   GdaStatement ** query);
48 
49 static void set_resultset_value (GdaXsltIntCont * pdata,
50 				 const char *resultset_name,
51 				 GObject * result, GError ** error);
52 static int get_resultset_col_value (GdaXsltIntCont * pdata,
53 				    const char *resultset_name,
54 				    const char *colname, char **outvalue,
55 				    GError ** error);
56 static int get_resultset_nodeset (GdaXsltIntCont * pdata,
57 				  const char *resultset_name,
58 				  xmlXPathObjectPtr * nodeset,
59 				  GError ** error);
60 static int _utility_data_model_to_nodeset (GdaDataModel * model,
61 					   xmlXPathObjectPtr * nodeset,
62 					   GError ** error);
63 static int gda_xslt_bk_internal_query (GdaXsltExCont * exec,
64 				       GdaXsltIntCont * pdata,
65 				       xsltTransformContextPtr ctxt,
66 				       xmlNodePtr query_node);
67 
68 int
_gda_xslt_holder_set_value(GdaHolder * param,xsltTransformContextPtr ctxt)69 _gda_xslt_holder_set_value (GdaHolder *param, xsltTransformContextPtr ctxt)
70 {
71 	GType gdatype;
72 	gchar *name;
73 	GValue *value;
74 	xmlChar *xvalue;
75 	xmlXPathObjectPtr xsltvar;
76 
77 	/* information from libgda */
78 	gdatype = gda_holder_get_g_type (param);
79 	name = gda_text_to_alphanum (gda_holder_get_id (param));
80 
81 	/* information from libxslt and libxml */
82 	xsltvar = xsltVariableLookup (ctxt, (const xmlChar *) name, NULL);
83 	xvalue = xmlXPathCastToString (xsltvar);
84 
85 	value = g_new0 (GValue, 1);
86 	if (!gda_value_set_from_string (value, (gchar *) xvalue, gdatype)) {
87 		/* error */
88 		g_free (value);
89 		g_free (xvalue);
90 		return -1;
91 	}
92 	else {
93 		gint retval = 0;
94 		if (! gda_holder_set_value (param, value, NULL))
95 			retval = -1;
96 		g_free (xvalue);
97 		gda_value_free (value);
98 		return retval;
99 	}
100 }
101 
102 int
_gda_xslt_bk_section(GdaXsltExCont * exec,GdaXsltIntCont * pdata,xsltTransformContextPtr ctxt,xmlNodePtr node,xmlNodePtr inst,G_GNUC_UNUSED xsltStylePreCompPtr comp)103 _gda_xslt_bk_section (GdaXsltExCont * exec, GdaXsltIntCont * pdata,
104 		     xsltTransformContextPtr ctxt, xmlNodePtr node,
105 		     xmlNodePtr inst, G_GNUC_UNUSED xsltStylePreCompPtr comp)
106 {
107 	xmlNode *cur_node = NULL;
108 	xmlNode *query_node = NULL;
109 	xmlNode *template_node = NULL;
110 	int res;
111 
112 	for (cur_node = inst->children; cur_node; cur_node = cur_node->next) {
113 		if (cur_node->type == XML_ELEMENT_NODE &&
114 		    xmlStrEqual (cur_node->ns->href,
115 				 BAD_CAST GDA_XSLT_EXTENSION_URI)) {
116 			printf ("found element in sql namespace: name[%s]\n",
117 				cur_node->name);
118 			if (xmlStrEqual
119 			    (cur_node->name,
120 			     BAD_CAST GDA_XSLT_ELEM_INTERNAL_QUERY)) {
121 				query_node = cur_node;
122 			}
123 			else if (xmlStrEqual
124 				 (cur_node->name,
125 				  BAD_CAST GDA_XSLT_ELEM_INTERNAL_TEMPLATE)) {
126 				template_node = cur_node;
127 			}
128 		}
129 	}
130 	if (query_node == NULL) {
131 		g_set_error (&(exec->error), 0, 0,
132 			     "%s", "no query node in section node");
133 		return -1;
134 	}
135 	/* set the query context */
136 	res = gda_xslt_bk_internal_query (exec, pdata, ctxt, query_node);
137 	if (res < 0) {
138 		printf ("sql_bk_internal_query res [%d]\n", res);
139 		return -1;
140 	}
141 	/* run the template */
142 	if (template_node) {
143 		/* template node must have only
144 		   xml comments and ONE xsl:call-template nodes */
145 		for (cur_node = template_node->children; cur_node;
146 		     cur_node = cur_node->next) {
147 			if (IS_XSLT_ELEM (cur_node)) {
148 				if (IS_XSLT_NAME (cur_node, "call-template")) {
149 					xsltStylePreCompPtr info =
150 						(xsltStylePreCompPtr)
151 						cur_node->psvi;
152 					if (info != NULL) {
153 						xsltCallTemplate
154 							(ctxt, node,
155 							 cur_node, info);
156 					}
157 					else {
158 						printf ("the xsltStylePreCompPtr is empthy\n");
159 						return -1;
160 					}
161 				}
162 				else {
163 #ifdef GDA_DEBUG_NO
164 					printf ("only one call-template node is allowed on sql:template node\n");
165 #endif
166 					return -1;
167 				}
168 			}
169 			else if (cur_node->type != XML_COMMENT_NODE) {
170 #ifdef GDA_DEBUG_NO
171 				printf ("only one xsl:call-template or comment node is allowed on sql:template node\n");
172 #endif
173 				return -1;
174 			}
175 		}
176 	}
177 	/* unset the query context */
178 // TODO, delete the query result information and the query if it was created inline
179 	return 0;
180 
181 }
182 
183 xmlXPathObjectPtr
_gda_xslt_bk_fun_getnodeset(xmlChar * set,GdaXsltExCont * exec,GdaXsltIntCont * pdata)184 _gda_xslt_bk_fun_getnodeset (xmlChar * set, GdaXsltExCont * exec,
185 			    GdaXsltIntCont * pdata)
186 {
187 	xmlXPathObjectPtr nodeset;
188 	int res;
189 #ifdef GDA_DEBUG_NO
190 	printf ("running function:_gda_xslt_bk_fun_getnodeset\n");
191 #endif
192 	res = get_resultset_nodeset (pdata, (gchar*) set, &nodeset, &(exec->error));
193 	if (res < 0 || nodeset == NULL) {
194 		xsltGenericError (xsltGenericErrorContext,
195 				  "_gda_xslt_bk_fun_getnodeset error\n");
196 		return NULL;
197 	}
198 	return nodeset;
199 }
200 
201 xmlXPathObjectPtr
_gda_xslt_bk_fun_getvalue(xmlChar * set,xmlChar * name,GdaXsltExCont * exec,GdaXsltIntCont * pdata,int getXml)202 _gda_xslt_bk_fun_getvalue (xmlChar * set, xmlChar * name, GdaXsltExCont * exec,
203 			  GdaXsltIntCont * pdata,int getXml)
204 {
205 	xmlXPathObjectPtr value;
206 	int res;
207 	xmlDocPtr sqlxmldoc;
208 	xmlNodePtr rootnode;
209 	xmlNodePtr copyrootnode;
210 #ifdef GDA_DEBUG_NO
211 	g_print ("running function:_gda_xslt_bk_fun_getvalue (getxml [%d])", getXml);
212 #endif
213 	char *strvalue;
214 	res = get_resultset_col_value (pdata, (const char *) set,
215 				       (const char *) name, &strvalue,
216 				       &(exec->error));
217 	if (res < 0) {
218 		xsltGenericError (xsltGenericErrorContext,
219 				  "_gda_xslt_bk_fun_getvalue: internal error on get_resultset_col_value\n");
220 		return NULL;
221 	}
222 
223 	if( getXml) {
224 		sqlxmldoc = xmlParseDoc((const xmlChar *)strvalue);
225 		if (sqlxmldoc == NULL) {
226 			xsltGenericError (xsltGenericErrorContext,
227 					"_gda_xslt_bk_fun_getvalue: xmlParseDoc fauld\n");
228 			return NULL;
229 		}
230 		rootnode = xmlDocGetRootElement(sqlxmldoc);
231 		copyrootnode = xmlCopyNode(rootnode,1);
232 		if (copyrootnode == NULL) {
233 			xsltGenericError (xsltGenericErrorContext,
234 					"_gda_xslt_bk_fun_getvalue: get or copy of root node fauld\n");
235 			return NULL;
236 		}
237 		value = (xmlXPathObjectPtr) xmlXPathNewNodeSet (copyrootnode);
238 		xmlFreeDoc(sqlxmldoc );
239 	} else {
240 		value = (xmlXPathObjectPtr) xmlXPathNewCString ((const char *)
241 								strvalue);
242 	}
243 
244 	if (value == NULL) {
245 		xsltGenericError (xsltGenericErrorContext,
246 				  "_gda_xslt_bk_fun_getvalue: internal error\n");
247 		return NULL;
248 	}
249 	return value;
250 }
251 
252 xmlXPathObjectPtr
_gda_xslt_bk_fun_checkif(G_GNUC_UNUSED xmlChar * setname,G_GNUC_UNUSED xmlChar * sql_condition,G_GNUC_UNUSED GdaXsltExCont * exec,G_GNUC_UNUSED GdaXsltIntCont * pdata)253 _gda_xslt_bk_fun_checkif (G_GNUC_UNUSED xmlChar * setname, G_GNUC_UNUSED xmlChar * sql_condition,
254 			 G_GNUC_UNUSED GdaXsltExCont * exec, G_GNUC_UNUSED GdaXsltIntCont * pdata)
255 {
256 	return xmlXPathNewBoolean (1);
257 }
258 
259 
260 
261 /* utility functions */
262 static void
set_resultset_value(GdaXsltIntCont * pdata,const char * resultset_name,GObject * result,G_GNUC_UNUSED GError ** error)263 set_resultset_value (GdaXsltIntCont * pdata, const char *resultset_name,
264 		     GObject * result, G_GNUC_UNUSED GError ** error)
265 {
266 #ifdef GDA_DEBUG_NO
267 	g_print ("new resultset: name[%s]", resultset_name);
268 #endif
269 	g_hash_table_insert (pdata->result_sets, g_strdup (resultset_name),
270 			     (gpointer) result);
271 }
272 
273 static int
get_resultset_col_value(GdaXsltIntCont * pdata,const char * resultset_name,const char * colname,char ** outvalue,GError ** error)274 get_resultset_col_value (GdaXsltIntCont * pdata, const char *resultset_name,
275 			 const char *colname, char **outvalue,
276 			 GError ** error)
277 {
278 	gpointer orig_key = NULL;
279 	gpointer value = NULL;
280 	GObject *result;
281 #ifdef GDA_DEBUG_NO
282 	g_print ("searching resultset[%s]", resultset_name);
283 #endif
284 
285 	if (g_hash_table_lookup_extended
286 	    (pdata->result_sets, resultset_name, &orig_key, &value)) {
287 #ifdef GDA_DEBUG_NO
288 		g_print ("resultset found [%p]", value);
289 #endif
290 		result = (GObject *) value;
291 	}
292 	else {
293 #ifdef GDA_DEBUG_NO
294 		g_print ("no resultset found");
295 #endif
296 		*outvalue = NULL;
297 		return -1;
298 	}
299 
300 	if (!GDA_IS_DATA_MODEL (result)) {
301 #ifdef GDA_DEBUG_NO
302 		g_print ("this is not a data model, returning NULL");
303 #endif
304 		*outvalue = NULL;
305 		return -1;
306 	}
307 	gint col_index;
308 	col_index = gda_data_model_get_column_index (GDA_DATA_MODEL (result), colname);
309 	if (col_index < 0) {
310 #ifdef GDA_DEBUG_NO
311 		g_print ("no column found by name [%s]", colname);
312 #endif
313 		*outvalue = NULL;
314 		return -1;
315 	}
316 	const GValue *db_value;
317 	db_value = gda_data_model_get_value_at (GDA_DATA_MODEL (result), col_index, 0, error);
318 	if (db_value == NULL) {
319 #ifdef GDA_DEBUG_NO
320 		g_print ("no value found on col_index [%d]", col_index);
321 #endif
322 		*outvalue = NULL;
323 		return -1;
324 	}
325 	gchar *gvalue_string;
326 	gvalue_string = (gchar*) value_to_xmlchar (db_value);
327 	if (gvalue_string == NULL) {
328 #ifdef GDA_DEBUG_NO
329 		g_print ("faild to stringify gvalue");
330 #endif
331 		*outvalue = NULL;
332 		return -1;
333 	}
334 	*outvalue = g_strdup (gvalue_string);
335 	g_free (gvalue_string);
336 	return 0;
337 }
338 
339 static int
get_resultset_nodeset(GdaXsltIntCont * pdata,const char * resultset_name,xmlXPathObjectPtr * nodeset,GError ** error)340 get_resultset_nodeset (GdaXsltIntCont * pdata, const char *resultset_name,
341 		       xmlXPathObjectPtr * nodeset, GError ** error)
342 {
343 	gpointer orig_key = NULL;
344 	gpointer value = NULL;
345 	GObject *result;
346 	int res;
347 #ifdef GDA_DEBUG_NO
348 	g_print ("searching resultset[%s]", resultset_name);
349 #endif
350 
351 	if (g_hash_table_lookup_extended
352 	    (pdata->result_sets, resultset_name, &orig_key, &value)) {
353 #ifdef GDA_DEBUG_NO
354 		g_print ("resultset found [%p]\n", value);
355 #endif
356 		result = (GObject *) value;
357 	}
358 	else {
359 #ifdef GDA_DEBUG_NO
360 		g_print ("no resultset found\n");
361 #endif
362 		g_set_error (error, 0, 0,
363 			     "no resultset found for name [%s]\n",
364 			     resultset_name);
365 		*nodeset = NULL;
366 		return -1;
367 	}
368 // Dont check if this is a Data Model, because saving the result we alreally check
369 	res = _utility_data_model_to_nodeset (GDA_DATA_MODEL (result),
370 					      nodeset, error);
371 	if (res < 0) {
372 #ifdef GDA_DEBUG_NO
373 		g_print ("_utility_data_model_to_nodeset fault");
374 #endif
375 		*nodeset = NULL;
376 		return -1;
377 	}
378 	return 0;
379 }
380 
381 /* -------------------------------------------------- */
382 static int
_utility_data_model_to_nodeset(GdaDataModel * model,xmlXPathObjectPtr * nodeset,GError ** error)383 _utility_data_model_to_nodeset (GdaDataModel * model,
384 				xmlXPathObjectPtr * nodeset, GError ** error)
385 {
386 	gint nrows, i;
387 	gint *rcols, rnb_cols;
388 	gchar **col_ids = NULL;
389 	gint c;
390 
391 	xmlNodePtr mainnode;
392 	mainnode = xmlNewNode (NULL, (xmlChar *) "resultset");
393 	if (mainnode == NULL) {
394 #ifdef GDA_DEBUG_NO
395 		g_print ("xmlNewNode return NULL\n");
396 #endif
397 		g_set_error (error, 0, 0, "%s", "xmlNewNode return NULL\n");
398 		return -1;
399 	}
400 	/* compute columns */
401 	rnb_cols = gda_data_model_get_n_columns (model);
402 	rcols = g_new (gint, rnb_cols);
403 	for (i = 0; i < rnb_cols; i++)
404 		rcols[i] = i;
405 
406 	col_ids = g_new0 (gchar *, rnb_cols);
407 	for (c = 0; c < rnb_cols; c++) {
408 		GdaColumn *column;
409 		const gchar *name;
410 		column = gda_data_model_describe_column (model, rcols[c]);
411 		name = gda_column_get_name (column);
412 		if (name)
413 			col_ids[c] = g_strdup (name);
414 		else
415 			col_ids[c] = g_strdup_printf ("_%d", c);
416 	}
417 
418 	/* add the model data to the XML output */
419 	nrows = gda_data_model_get_n_rows (model);
420 	if (nrows > 0) {
421 		xmlNodePtr row, field;
422 		gint r, c;
423 		for (r = 0; r < nrows; r++) {
424 			row = xmlNewChild (mainnode, NULL, (xmlChar *) "row", NULL);
425 			for (c = 0; c < rnb_cols; c++) {
426 				GValue *value;
427 				xmlChar *str = NULL;
428 				gboolean isnull = FALSE;
429 
430 				value = (GValue *) gda_data_model_get_value_at (model, rcols[c], r, error);
431 				if (!value) {
432 					for (c = 0; c < rnb_cols; c++)
433 						g_free (col_ids[c]);
434 					g_free (col_ids);
435 					g_free (rcols);
436 					return -1;
437 				}
438 				if (gda_value_is_null ((GValue *) value))
439 					isnull = TRUE;
440 				else
441 					str = value_to_xmlchar (value);
442 				field = xmlNewTextChild (row, NULL, (xmlChar *) "column", (xmlChar *) str);
443 				xmlSetProp (field, (xmlChar *) "name", (xmlChar *) col_ids[c]);
444 				if (isnull)
445 					xmlSetProp (field, (xmlChar *) "isnull", (xmlChar *) "true");
446 				g_free (str);
447 			}
448 		}
449 	}
450 	for (c = 0; c < rnb_cols; c++)
451 		g_free (col_ids[c]);
452 	g_free (col_ids);
453 	g_free (rcols);
454 
455 	*nodeset = (xmlXPathObjectPtr) xmlXPathNewNodeSet (mainnode);
456 
457 	return 0;
458 }
459 
460 static void
look_predefined_query_by_name(GdaXsltExCont * exec,const char * query_name,GdaStatement ** query)461 look_predefined_query_by_name (GdaXsltExCont * exec, const char *query_name,
462 			       GdaStatement ** query)
463 {
464 	gpointer orig_key = NULL;
465 	gpointer value = NULL;
466 #ifdef GDA_DEBUG_NO
467 	g_print ("searching predefined query name[%s]", query_name);
468 #endif
469 
470 	if (g_hash_table_lookup_extended
471 	    (exec->query_hash, query_name, &orig_key, &value)) {
472 #ifdef GDA_DEBUG_NO
473 		g_print ("query found [%p]", value);
474 #endif
475 		*query = (GdaStatement *) value;
476 	}
477 	else {
478 #ifdef GDA_DEBUG_NO
479 		g_print ("no predefined query found");
480 #endif
481 		*query = NULL;
482 	}
483 }
484 
485 static int
gda_xslt_bk_internal_query(GdaXsltExCont * exec,GdaXsltIntCont * pdata,xsltTransformContextPtr ctxt,xmlNodePtr query_node)486 gda_xslt_bk_internal_query (GdaXsltExCont * exec, GdaXsltIntCont * pdata,
487 			    xsltTransformContextPtr ctxt,
488 			    xmlNodePtr query_node)
489 {
490 	GdaStatement *query = NULL;
491 	GdaSet *params;
492 	int ret = 0;
493 	GdaDataModel *resQuery;
494 	GSList *plist;
495 	int predefined = 0;
496 
497 	xmlNodePtr sqltxt_node = NULL;
498 	xmlChar *query_name;
499 
500 #ifdef GDA_DEBUG_NO
501 	g_print ("running function:gda_xslt_bk_internal_query \n");
502 #endif
503 
504 	query_name = xmlGetProp (query_node, (const xmlChar *) "name");
505 	if (query_name == NULL) {
506 		g_set_error (&(exec->error), 0, 0,
507 			     "%s", "the query element is not correct, no 'name' attribute\n");
508 		return -1;
509 	}
510 
511 	look_predefined_query_by_name (exec, (gchar*) query_name, &(query));
512 	if (!query) {
513 		/* the query is not predefined */
514 		/* get the xml text node with the sql */
515 		sqltxt_node = query_node->children;
516 		if (sqltxt_node == NULL || sqltxt_node->type != XML_TEXT_NODE) {
517 			g_set_error (&(exec->error), 0, 0,
518 				     "%s", "the query element is not correct, it have not a first text children\n");
519 			return -1;
520 		}
521 #ifdef GDA_DEBUG_NO
522 		printf ("query_content[%s]\n", XML_GET_CONTENT (sqltxt_node));
523 #endif
524 		/* create the query */
525 		GdaSqlParser *parser;
526 		parser = gda_connection_create_parser (exec->cnc);
527 		query = gda_sql_parser_parse_string (parser, (gchar*) XML_GET_CONTENT (sqltxt_node), NULL, &(exec->error));
528 		g_object_unref (parser);
529 		if (!query) {
530 #ifdef GDA_DEBUG_NO
531 			g_print ("gda_query_new_from_sql:error [%s]\n",
532 				 exec->error && exec->error->message ? exec->error->
533 				 message : "No detail");
534 #endif
535 			return -1;
536 		}
537 	}
538 	else {
539 		/* the query is predefined */
540 		predefined = 1;
541 	}
542 
543 	/* find the parameters on xsltcontext */
544 	if (! gda_statement_get_parameters (query, &params, &(exec->error)))
545 		return -1;
546 
547 	if (params != NULL) {
548 		plist = params->holders;
549 		while (plist && ret == 0) {
550 			ret = _gda_xslt_holder_set_value (GDA_HOLDER (plist->data), ctxt);
551 			plist = g_slist_next (plist);
552 		}
553 	}
554 
555 	/* run the query */
556 	resQuery = gda_connection_statement_execute_select (exec->cnc, query, params, &(exec->error));
557 	if (!resQuery) {
558 #ifdef GDA_DEBUG_NO
559 		g_print ("gda_query_execute:error [%s]\n",
560 			 exec->error
561 			 && exec->error->message ? exec->error->
562 			 message : "No detail");
563 #endif
564 		return -1;
565 	}
566 
567 	/* save the result to the internal context */
568 	set_resultset_value (pdata, (const char *) query_name, (GObject*) resQuery, &(exec->error));
569 
570 	/* free the parameters */
571 	if (params)
572 		g_object_unref (params);
573 	/* free the query if not predefined */
574 	if (!predefined && query)
575 		g_object_unref (query);
576 	xmlFree (query_name);
577 	return 0;
578 }
579 
580 
581 /* from libgda */
582 static gboolean
gtype_equal(gconstpointer a,gconstpointer b)583 gtype_equal (gconstpointer a, gconstpointer b)
584 {
585 	return (GType) a == (GType) b ? TRUE : FALSE;
586 }
587 
588 static xmlChar *
value_to_xmlchar(const GValue * value)589 value_to_xmlchar (const GValue * value)
590 {
591 	GdaDataHandler *dh;
592 	gchar *str;
593 
594 	if (!value || gda_value_is_null (value))
595 		return (BAD_CAST "");
596 	else if ((G_VALUE_TYPE (value) == GDA_TYPE_BINARY) ||
597 		 (G_VALUE_TYPE (value) == GDA_TYPE_BLOB)) {
598 		TO_IMPLEMENT;
599 		return (BAD_CAST "Binary data");
600 	}
601 	if (!data_handlers) {
602 		/* initialize the internal data handlers */
603 		data_handlers =
604 			g_hash_table_new_full (g_direct_hash, gtype_equal,
605 					       NULL, (GDestroyNotify)
606 					       g_object_unref);
607 
608 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_INT64,
609 				     gda_handler_numerical_new ());
610 		g_hash_table_insert (data_handlers,
611 				     (gpointer) G_TYPE_UINT64,
612 				     gda_handler_numerical_new ());
613 		g_hash_table_insert (data_handlers,
614 				     (gpointer) G_TYPE_BOOLEAN,
615 				     gda_handler_boolean_new ());
616 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_DATE,
617 				     gda_handler_time_new ());
618 		g_hash_table_insert (data_handlers,
619 				     (gpointer) G_TYPE_DOUBLE,
620 				     gda_handler_numerical_new ());
621 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_INT,
622 				     gda_handler_numerical_new ());
623 		g_hash_table_insert (data_handlers,
624 				     (gpointer) GDA_TYPE_NUMERIC,
625 				     gda_handler_numerical_new ());
626 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_FLOAT,
627 				     gda_handler_numerical_new ());
628 		g_hash_table_insert (data_handlers,
629 				     (gpointer) GDA_TYPE_SHORT,
630 				     gda_handler_numerical_new ());
631 		g_hash_table_insert (data_handlers,
632 				     (gpointer) GDA_TYPE_USHORT,
633 				     gda_handler_numerical_new ());
634 		g_hash_table_insert (data_handlers,
635 				     (gpointer) G_TYPE_STRING,
636 				     gda_handler_string_new ());
637 		g_hash_table_insert (data_handlers,
638 				     (gpointer) GDA_TYPE_TIME,
639 				     gda_handler_time_new ());
640 		g_hash_table_insert (data_handlers,
641 				     (gpointer) GDA_TYPE_TIMESTAMP,
642 				     gda_handler_time_new ());
643 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_CHAR,
644 				     gda_handler_numerical_new ());
645 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_UCHAR,
646 				     gda_handler_numerical_new ());
647 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_ULONG,
648 				     gda_handler_numerical_new ());
649 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_LONG,
650 				     gda_handler_numerical_new ());
651 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_GTYPE,
652 				     gda_handler_type_new ());
653 		g_hash_table_insert (data_handlers, (gpointer) G_TYPE_UINT,
654 				     gda_handler_numerical_new ());
655 	}
656 
657 	dh = g_hash_table_lookup (data_handlers,
658 				  (gpointer) G_VALUE_TYPE (value));
659 	if (dh)
660 		str = gda_data_handler_get_str_from_value (dh, value);
661 	else
662 		str = gda_value_stringify (value);
663 	return (BAD_CAST (str ? str : ""));
664 }
665