1 /*
2  * Copyright (C) 2007 - 2011 Vivien Malerba <malerba@gnome-db.org>
3  * Copyright (C) 2010 David King <davidk@openismus.com>
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 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <time.h>
25 #include <string.h>
26 #include <errno.h>
27 
28 #include <libxml/xpathInternals.h>
29 
30 #include <libgda-xslt.h>
31 #include "sql_backend.h"
32 
33 
34 static void gda_xslt_getnodeset_function (xmlXPathParserContextPtr ctxt,
35 					  int nargs);
36 static void gda_xslt_checkif_function (xmlXPathParserContextPtr ctxt,
37 				       int nargs);
38 static void gda_xslt_getvalue_function (xmlXPathParserContextPtr ctxt,
39 					int nargs);
40 static void gda_xslt_getxmlvalue_function (xmlXPathParserContextPtr ctxt,
41 					int nargs);
42 static void gda_xslt_section_element (xsltTransformContextPtr tctxt,
43 				      xmlNodePtr node, xmlNodePtr inst,
44 				      xsltStylePreCompPtr comp);
45 
46 void *
47 _gda_xslt_extension_init (xsltTransformContextPtr ctxt, const xmlChar * URI)
48 {
49 	int res;
50 	GdaXsltIntCont *data;
51 #ifdef GDA_DEBUG_NO
52 	g_print ("_gda_xslt_extension_init");
53 #endif
54 	if (!URI || strcmp ((gchar*) URI, GDA_XSLT_EXTENSION_URI)) {
55 #ifdef GDA_DEBUG_NO
56 		g_print ("called for another URI, exit");
57 #endif
58 		return NULL;
59 	}
60 
61 	data = calloc (1, sizeof (GdaXsltIntCont));
62 	if (data == NULL) {
63 #ifdef GDA_DEBUG_NO
64 		g_print ("no memory");
65 #endif
66 		return NULL;
67 	}
68 #ifdef GDA_DEBUG_NO
_gda_xslt_holder_set_value(GdaHolder * param,xsltTransformContextPtr ctxt)69 	g_print ("initialize result_sets hash");
70 #endif
71 	data->result_sets =
72 		g_hash_table_new_full (g_str_hash, g_str_equal,
73 				       g_free,
74 				       NULL);
75 
76 	res = xsltRegisterExtFunction (ctxt,
77 				       (const xmlChar *)
78 				       GDA_XSLT_FUNC_GETVALUE, URI,
79 				       gda_xslt_getvalue_function);
80 	res = xsltRegisterExtFunction (ctxt,
81 				       (const xmlChar *)
82 				       GDA_XSLT_FUNC_GETXMLVALUE, URI,
83 				       gda_xslt_getxmlvalue_function);
84 	res |= xsltRegisterExtFunction (ctxt,
85 					(const xmlChar *)
86 					GDA_XSLT_FUNC_CHECKIF, URI,
87 					gda_xslt_checkif_function);
88 	res |= xsltRegisterExtFunction (ctxt,
89 					(const xmlChar *)
90 					GDA_XSLT_FUNC_GETNODESET, URI,
91 					gda_xslt_getnodeset_function);
92 	if (res != 0) {
93 		g_error ("failed to xsltRegisterExtFunction = [%d]", res);
94 	}
95 
96 	res = xsltRegisterExtElement (ctxt,
97 				      (const xmlChar *) GDA_XSLT_ELEM_SECTION,
98 				      URI,
99 				      (xsltTransformFunction)
100 				      gda_xslt_section_element);
101 	if (res != 0) {
102 		g_error ("failed to xsltRegisterExtElement = [%d]", res);
_gda_xslt_bk_section(GdaXsltExCont * exec,GdaXsltIntCont * pdata,xsltTransformContextPtr ctxt,xmlNodePtr node,xmlNodePtr inst,G_GNUC_UNUSED xsltStylePreCompPtr comp)103 	}
104 	return data;
105 }
106 
107 void
108 _gda_xslt_extension_shutdown (G_GNUC_UNUSED xsltTransformContextPtr ctxt,
109 			     G_GNUC_UNUSED const xmlChar * URI, void *data)
110 {
111 	GdaXsltIntCont *p_data = (GdaXsltIntCont *) data;
112 	if (p_data) {
113 		free (p_data);
114 	}
115 }
116 
117 static void
118 gda_xslt_getnodeset_function (xmlXPathParserContextPtr ctxt, int nargs)
119 {
120 	GdaXsltIntCont *data;
121 	xsltTransformContextPtr tctxt;
122 	xmlXPathObjectPtr setname, nodeset;
123 	GdaXsltExCont *execc;
124 	if (nargs != 1) {
125 		xsltGenericError (xsltGenericErrorContext,
126 				  "gda_xslt_getnodeset_function: invalid number of arguments\n");
127 		return;
128 	}
129 	tctxt = xsltXPathGetTransformContext (ctxt);
130 	if (tctxt == NULL) {
131 		xsltGenericError (xsltGenericErrorContext,
132 				  "sqlxslt: failed to get the transformation context\n");
133 		return;
134 	}
135 	execc = (GdaXsltExCont *) tctxt->_private;
136 	data = (GdaXsltIntCont *) xsltGetExtData (tctxt,
137 						  BAD_CAST GDA_XSLT_EXTENSION_URI);
138 	if (data == NULL) {
139 		xsltGenericError (xsltGenericErrorContext,
140 				  "sqlxslt: failed to get module data\n");
141 		return;
142 	}
143 	setname = valuePop (ctxt);
144 	if (setname == NULL) {
145 		xsltGenericError (xsltGenericErrorContext,
146 				  "sqlxslt: internal error\n");
147 		return;
148 	}
149 
150 	if (setname->type != XPATH_STRING) {
151 		valuePush (ctxt, setname);
152 		xmlXPathStringFunction (ctxt, 1);
153 		setname = valuePop (ctxt);
154 		if (setname == NULL) {
155 			xsltGenericError (xsltGenericErrorContext,
156 					  "sqlxslt: internal error\n");
157 			return;
158 		}
159 	}
160 	nodeset =
161 		_gda_xslt_bk_fun_getnodeset (setname->stringval, execc, data);
162 	if (nodeset == NULL) {
163 		xsltGenericError (xsltGenericErrorContext,
164 				  "exsltDynMapFunctoin: ret == NULL\n");
165 		return;
166 	}
167 	valuePush (ctxt, nodeset);
168 }
169 
170 static void
171 gda_xslt_checkif_function (xmlXPathParserContextPtr ctxt, int nargs)
172 {
173 	GdaXsltIntCont *data;
174 	xsltTransformContextPtr tctxt;
175 	xmlXPathObjectPtr setname, sql, value;
176 	GdaXsltExCont *execc;
177 	if (nargs != 2) {
178 		xsltGenericError (xsltGenericErrorContext,
179 				  "gda_xslt_checkif_function: invalid number of arguments\n");
180 		return;
181 	}
182 	tctxt = xsltXPathGetTransformContext (ctxt);
183 	if (tctxt == NULL) {
_gda_xslt_bk_fun_getnodeset(xmlChar * set,GdaXsltExCont * exec,GdaXsltIntCont * pdata)184 		xsltGenericError (xsltGenericErrorContext,
185 				  "gda_xslt_checkif_function: failed to get the transformation context\n");
186 		return;
187 	}
188 	execc = (GdaXsltExCont *) tctxt->_private;
189 	data = (GdaXsltIntCont *) xsltGetExtData (tctxt,
190 						  BAD_CAST GDA_XSLT_EXTENSION_URI);
191 	if (data == NULL || execc == NULL) {
192 		xsltGenericError (xsltGenericErrorContext,
193 				  "gda_xslt_checkif_function: failed to get module internal data\n");
194 		return;
195 	}
196 	sql = valuePop (ctxt);
197 	setname = valuePop (ctxt);
198 	if (sql == NULL || setname == NULL) {
199 		xsltGenericError (xsltGenericErrorContext,
200 				  "gda_xslt_checkif_function: internal error\n");
201 		return;
_gda_xslt_bk_fun_getvalue(xmlChar * set,xmlChar * name,GdaXsltExCont * exec,GdaXsltIntCont * pdata,int getXml)202 	}
203 
204 	if (sql->type != XPATH_STRING) {
205 		valuePush (ctxt, sql);
206 		xmlXPathStringFunction (ctxt, 1);
207 		sql = valuePop (ctxt);
208 		if (sql == NULL) {
209 			xsltGenericError (xsltGenericErrorContext,
210 					  "sqlxslt: internal error. sql parameter is not a string\n");
211 			return;
212 		}
213 	}
214 	if (setname->type != XPATH_STRING) {
215 		valuePush (ctxt, setname);
216 		xmlXPathStringFunction (ctxt, 1);
217 		setname = valuePop (ctxt);
218 		if (setname == NULL) {
219 			xsltGenericError (xsltGenericErrorContext,
220 					  "sqlxslt: internal error. Setname parameter is not a string\n");
221 			return;
222 		}
223 	}
224 	value = _gda_xslt_bk_fun_checkif (setname->stringval, sql->stringval,
225 					 execc, data);
226 	if (value == NULL) {
227 		xsltGenericError (xsltGenericErrorContext,
228 				  "sqlxslt: internal error. Empty value\n");
229 		return;
230 	}
231 	valuePush (ctxt, value);
232 }
233 
234 static void
235 gda_xslt_getvalue_function (xmlXPathParserContextPtr ctxt, int nargs)
236 {
237 	GdaXsltIntCont *data;
238 	xsltTransformContextPtr tctxt;
239 	xmlXPathObjectPtr set, name, value;
240 	GdaXsltExCont *execc;
241 
242 	if (nargs != 2) {
243 		xsltGenericError (xsltGenericErrorContext,
244 				  "gda_xslt_getvalue_function: invalid number of arguments\n");
245 		return;
246 	}
247 	tctxt = xsltXPathGetTransformContext (ctxt);
248 	if (tctxt == NULL) {
249 		xsltGenericError (xsltGenericErrorContext,
250 				  "gda_xslt_getvalue_function: failed to get the transformation context\n");
251 		return;
252 	}
_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 
254 	execc = (GdaXsltExCont *) tctxt->_private;
255 	data = (GdaXsltIntCont *) xsltGetExtData (tctxt,
256 						  BAD_CAST GDA_XSLT_EXTENSION_URI);
257 	if (data == NULL || execc == NULL) {
258 		xsltGenericError (xsltGenericErrorContext,
259 				  "gda_xslt_getvalue_function: failed to get module internal data\n");
260 		return;
261 	}
262 	name = valuePop (ctxt);
set_resultset_value(GdaXsltIntCont * pdata,const char * resultset_name,GObject * result,G_GNUC_UNUSED GError ** error)263 	set = valuePop (ctxt);
264 	if (name == NULL || set == NULL) {
265 		xsltGenericError (xsltGenericErrorContext,
266 				  "gda_xslt_getvalue_function: internal error\n");
267 		return;
268 	}
269 
270 	if (name->type != XPATH_STRING) {
271 		valuePush (ctxt, name);
272 		xmlXPathStringFunction (ctxt, 1);
273 		name = valuePop (ctxt);
get_resultset_col_value(GdaXsltIntCont * pdata,const char * resultset_name,const char * colname,char ** outvalue,GError ** error)274 		if (name == NULL) {
275 			xsltGenericError (xsltGenericErrorContext,
276 					  "gda_xslt_getvalue_function: internal error. Name parameter is not a string\n");
277 			return;
278 		}
279 	}
280 	if (set->type != XPATH_STRING) {
281 		valuePush (ctxt, set);
282 		xmlXPathStringFunction (ctxt, 1);
283 		set = valuePop (ctxt);
284 		if (set == NULL) {
285 			xsltGenericError (xsltGenericErrorContext,
286 					  "gda_xslt_getvalue_function: internal error. Set parameter is not a string\n");
287 			return;
288 		}
289 	}
290 
291 	value = _gda_xslt_bk_fun_getvalue (set->stringval, name->stringval,
292 					  execc, data,0);
293 	if (value == NULL) {
294 		xsltGenericError (xsltGenericErrorContext,
295 				  "gda_xslt_getvalue_function: internal error. Empty value\n");
296 		return;
297 	}
298 	valuePush (ctxt, value);
299 }
300 
301 static void
302 gda_xslt_getxmlvalue_function (xmlXPathParserContextPtr ctxt, int nargs)
303 {
304 	GdaXsltIntCont *data;
305 	xsltTransformContextPtr tctxt;
306 	xmlXPathObjectPtr set, name, value;
307 	GdaXsltExCont *execc;
308 
309 	if (nargs != 2) {
310 		xsltGenericError (xsltGenericErrorContext,
311 				  "gda_xslt_getxmlvalue_function: invalid number of arguments\n");
312 		return;
313 	}
314 	tctxt = xsltXPathGetTransformContext (ctxt);
315 	if (tctxt == NULL) {
316 		xsltGenericError (xsltGenericErrorContext,
317 				  "gda_xslt_getxmlvalue_function: failed to get the transformation context\n");
318 		return;
319 	}
320 
321 	execc = (GdaXsltExCont *) tctxt->_private;
322 	data = (GdaXsltIntCont *) xsltGetExtData (tctxt,
323 						  BAD_CAST GDA_XSLT_EXTENSION_URI);
324 	if (data == NULL || execc == NULL) {
325 		xsltGenericError (xsltGenericErrorContext,
326 				  "gda_xslt_getxmlvalue_function: failed to get module internal data\n");
327 		return;
328 	}
329 	name = valuePop (ctxt);
330 	set = valuePop (ctxt);
331 	if (name == NULL || set == NULL) {
332 		xsltGenericError (xsltGenericErrorContext,
333 				  "gda_xslt_getxmlvalue_function: internal error\n");
334 		return;
335 	}
336 
337 	if (name->type != XPATH_STRING) {
338 		valuePush (ctxt, name);
339 		xmlXPathStringFunction (ctxt, 1);
get_resultset_nodeset(GdaXsltIntCont * pdata,const char * resultset_name,xmlXPathObjectPtr * nodeset,GError ** error)340 		name = valuePop (ctxt);
341 		if (name == NULL) {
342 			xsltGenericError (xsltGenericErrorContext,
343 					  "gda_xslt_getxmlvalue_function: internal error. Name parameter is not a string\n");
344 			return;
345 		}
346 	}
347 	if (set->type != XPATH_STRING) {
348 		valuePush (ctxt, set);
349 		xmlXPathStringFunction (ctxt, 1);
350 		set = valuePop (ctxt);
351 		if (set == NULL) {
352 			xsltGenericError (xsltGenericErrorContext,
353 					  "gda_xslt_getxmlvalue_function: internal error. Set parameter is not a string\n");
354 			return;
355 		}
356 	}
357 
358 	value = _gda_xslt_bk_fun_getvalue (set->stringval, name->stringval,
359 					  execc, data,1);
360 	if (value == NULL) {
361 		xsltGenericError (xsltGenericErrorContext,
362 				  "gda_xslt_getxmlvalue_function: internal error. Empty value\n");
363 		return;
364 	}
365 	valuePush (ctxt, value);
366 }
367 
368 static void
369 gda_xslt_section_element (xsltTransformContextPtr tctxt,
370 			  xmlNodePtr node,
371 			  xmlNodePtr inst, xsltStylePreCompPtr comp)
372 {
373 	int res;
374 	GdaXsltIntCont *data;
375 	GdaXsltExCont *execc;
376 
377 //   gda_xslt_dump_element(tctxt,node,inst,comp);
378 	if (tctxt == NULL || node == NULL || inst == NULL
379 	    || tctxt->insert == NULL) {
380 		xsltGenericError (xsltGenericErrorContext,
381 				  "gda_xslt_section_element: bad input date\n");
382 		tctxt->state = XSLT_STATE_STOPPED;
_utility_data_model_to_nodeset(GdaDataModel * model,xmlXPathObjectPtr * nodeset,GError ** error)383 		return;
384 	}
385 
386 	execc = (GdaXsltExCont *) tctxt->_private;
387 	data = (GdaXsltIntCont *) xsltGetExtData (tctxt,
388 						  BAD_CAST GDA_XSLT_EXTENSION_URI);
389 	if (data == NULL || execc == NULL) {
390 		xsltGenericError (xsltGenericErrorContext,
391 				  "gda_xslt_section_element: failed to get module internal data\n");
392 		tctxt->state = XSLT_STATE_STOPPED;
393 		return;
394 	}
395 	res = _gda_xslt_bk_section (execc, data, tctxt, node, inst, comp);
396 	if (res < 0) {
397 		xsltGenericError (xsltGenericErrorContext,
398 				  "gda_xslt_section_element: execute query backend\n");
399 		tctxt->state = XSLT_STATE_STOPPED;
400 		return;
401 	}
402 	return;
403 }
404