1 /* -*- Mode: c; c-basic-offset: 2 -*-
2  *
3  * rasqal_rowsource_source.c - Rasqal source rowsource class
4  *
5  * Copyright (C) 2008-2009, David Beckett http://www.dajobe.org/
6  *
7  * This package is Free Software and part of Redland http://librdf.org/
8  *
9  * It is licensed under the following three licenses as alternatives:
10  *   1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
11  *   2. GNU General Public License (GPL) V2 or any newer version
12  *   3. Apache License, V2.0 or any newer version
13  *
14  * You may not use this file except in compliance with at least one of
15  * the above three licenses.
16  *
17  * See LICENSE.html or LICENSE.txt at the top of this package for the
18  * complete terms and further detail along with the license texts for
19  * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
20  *
21  */
22 
23 
24 #ifdef HAVE_CONFIG_H
25 #include <rasqal_config.h>
26 #endif
27 
28 #ifdef WIN32
29 #include <win32_rasqal_config.h>
30 #endif
31 
32 #include <stdio.h>
33 #include <string.h>
34 #ifdef HAVE_STDLIB_H
35 #include <stdlib.h>
36 #endif
37 
38 #include <raptor.h>
39 
40 #include "rasqal.h"
41 #include "rasqal_internal.h"
42 
43 
44 #define DEBUG_FH stderr
45 
46 
47 typedef struct
48 {
49   /* inner rowsource to sort */
50   rasqal_rowsource *rowsource;
51 
52   /* sequence of order conditions #rasqal_expression (SHARED with query) */
53   raptor_sequence* order_seq;
54 
55   /* number of order conditions in order_seq */
56   int order_size;
57 
58   /* distinct flag */
59   int distinct;
60 
61   /* map for sorting */
62   rasqal_map* map;
63 
64   /* sequence of rows (owned here) */
65   raptor_sequence* seq;
66 } rasqal_sort_rowsource_context;
67 
68 
69 static int
rasqal_sort_rowsource_init(rasqal_rowsource * rowsource,void * user_data)70 rasqal_sort_rowsource_init(rasqal_rowsource* rowsource, void *user_data)
71 {
72   rasqal_query *query = rowsource->query;
73   rasqal_sort_rowsource_context *con;
74 
75   con = (rasqal_sort_rowsource_context*)user_data;
76 
77   if(con->order_seq)
78     con->order_size = raptor_sequence_size(con->order_seq);
79   else {
80     RASQAL_DEBUG1("No order conditions for sort rowsource - passing through");
81     con->order_size = -1;
82   }
83 
84   con->map = NULL;
85 
86   if(con->order_size > 0 ) {
87     /* make a row:NULL map in order to sort or do distinct
88      * FIXME: should DISTINCT be separate?
89      */
90     con->map = rasqal_engine_new_rowsort_map(con->distinct,
91                                              query->compare_flags,
92                                              con->order_seq);
93     if(!con->map)
94       return 1;
95   }
96 
97   con->seq = NULL;
98 
99   return 0;
100 }
101 
102 
103 static int
rasqal_sort_rowsource_process(rasqal_rowsource * rowsource,rasqal_sort_rowsource_context * con)104 rasqal_sort_rowsource_process(rasqal_rowsource* rowsource,
105                               rasqal_sort_rowsource_context* con)
106 {
107   int offset = 0;
108 
109   /* already processed */
110   if(con->seq)
111     return 0;
112 
113   con->seq = raptor_new_sequence((raptor_data_free_handler)rasqal_free_row,
114                                  (raptor_data_print_handler)rasqal_row_print);
115   if(!con->seq)
116     return 1;
117 
118   while(1) {
119     rasqal_row* row;
120 
121     row = rasqal_rowsource_read_row(con->rowsource);
122     if(!row)
123       break;
124 
125     if(rasqal_row_set_order_size(row, con->order_size)) {
126       rasqal_free_row(row);
127       return 1;
128     }
129 
130     rasqal_engine_rowsort_calculate_order_values(rowsource->query, con->order_seq, row);
131 
132     row->offset = offset;
133 
134     /* after this, row is owned by map */
135     if(!rasqal_engine_rowsort_map_add_row(con->map, row))
136       offset++;
137   }
138 
139 #ifdef RASQAL_DEBUG
140   fputs("resulting ", DEBUG_FH);
141   rasqal_map_print(con->map, DEBUG_FH);
142   fputs("\n", DEBUG_FH);
143 #endif
144 
145   /* do sort/distinct: walk map in order, adding rows to sequence */
146   rasqal_engine_rowsort_map_to_sequence(con->map, con->seq);
147   rasqal_free_map(con->map); con->map = NULL;
148 
149   return 0;
150 }
151 
152 
153 static int
rasqal_sort_rowsource_ensure_variables(rasqal_rowsource * rowsource,void * user_data)154 rasqal_sort_rowsource_ensure_variables(rasqal_rowsource* rowsource,
155                                        void *user_data)
156 {
157   rasqal_sort_rowsource_context* con;
158   con = (rasqal_sort_rowsource_context*)user_data;
159 
160   if(rasqal_rowsource_ensure_variables(con->rowsource))
161     return 1;
162 
163   rowsource->size = 0;
164   rasqal_rowsource_copy_variables(rowsource, con->rowsource);
165 
166   return 0;
167 }
168 
169 
170 static int
rasqal_sort_rowsource_finish(rasqal_rowsource * rowsource,void * user_data)171 rasqal_sort_rowsource_finish(rasqal_rowsource* rowsource, void *user_data)
172 {
173   rasqal_sort_rowsource_context *con;
174   con = (rasqal_sort_rowsource_context*)user_data;
175 
176   if(con->rowsource)
177     rasqal_free_rowsource(con->rowsource);
178 
179   if(con->map)
180     rasqal_free_map(con->map);
181 
182   if(con->seq)
183     raptor_free_sequence(con->seq);
184 
185   RASQAL_FREE(rasqal_sort_rowsource_context, con);
186 
187   return 0;
188 }
189 
190 
191 static raptor_sequence*
rasqal_sort_rowsource_read_all_rows(rasqal_rowsource * rowsource,void * user_data)192 rasqal_sort_rowsource_read_all_rows(rasqal_rowsource* rowsource,
193                                     void *user_data)
194 {
195   rasqal_sort_rowsource_context *con;
196   raptor_sequence *seq = NULL;
197 
198   con = (rasqal_sort_rowsource_context*)user_data;
199 
200   /* if there were no ordering conditions, pass it all on to inner rowsource */
201   if(con->order_size <= 0)
202     return rasqal_rowsource_read_all_rows(con->rowsource);
203 
204 
205   /* need to sort */
206   if(rasqal_sort_rowsource_process(rowsource, con))
207     return NULL;
208 
209   if(con->seq) {
210     /* pass ownership of seq back to caller */
211     seq = con->seq;
212     con->seq = NULL;
213   }
214 
215   return seq;
216 }
217 
218 
219 static rasqal_rowsource*
rasqal_sort_rowsource_get_inner_rowsource(rasqal_rowsource * rowsource,void * user_data,int offset)220 rasqal_sort_rowsource_get_inner_rowsource(rasqal_rowsource* rowsource,
221                                           void *user_data, int offset)
222 {
223   rasqal_sort_rowsource_context *con;
224   con = (rasqal_sort_rowsource_context*)user_data;
225 
226   if(offset == 0)
227     return con->rowsource;
228   return NULL;
229 }
230 
231 
232 static const rasqal_rowsource_handler rasqal_sort_rowsource_handler = {
233   /* .version =          */ 1,
234   "sort",
235   /* .init =             */ rasqal_sort_rowsource_init,
236   /* .finish =           */ rasqal_sort_rowsource_finish,
237   /* .ensure_variables = */ rasqal_sort_rowsource_ensure_variables,
238   /* .read_row =         */ NULL,
239   /* .read_all_rows =    */ rasqal_sort_rowsource_read_all_rows,
240   /* .reset =            */ NULL,
241   /* .set_requirements = */ NULL,
242   /* .get_inner_rowsource = */ rasqal_sort_rowsource_get_inner_rowsource,
243   /* .set_origin =       */ NULL,
244 };
245 
246 
247 /**
248  * rasqal_new_sort_rowsource:
249  * @world: query world
250  * @query: query results object
251  * @rowsource: input rowsource
252  * @order_seq: order sequence (shared, may be NULL)
253  * @distinct: distinct flag
254  *
255  * INTERNAL - create a SORT over rows from input rowsource
256  *
257  * The @rowsource becomes owned by the new rowsource.
258  *
259  * Return value: new rowsource or NULL on failure
260  */
261 rasqal_rowsource*
rasqal_new_sort_rowsource(rasqal_world * world,rasqal_query * query,rasqal_rowsource * rowsource,raptor_sequence * order_seq,int distinct)262 rasqal_new_sort_rowsource(rasqal_world *world,
263                           rasqal_query *query,
264                           rasqal_rowsource *rowsource,
265                           raptor_sequence* order_seq,
266                           int distinct)
267 {
268   rasqal_sort_rowsource_context *con;
269   int flags = 0;
270 
271   if(!world || !query || !rowsource)
272     goto fail;
273 
274   con = RASQAL_CALLOC(rasqal_sort_rowsource_context*, 1, sizeof(*con));
275   if(!con)
276     goto fail;
277 
278   con->rowsource = rowsource;
279   con->order_seq = order_seq;
280   con->distinct = distinct;
281 
282   return rasqal_new_rowsource_from_handler(world, query,
283                                            con,
284                                            &rasqal_sort_rowsource_handler,
285                                            query->vars_table,
286                                            flags);
287 
288   fail:
289   if(rowsource)
290     rasqal_free_rowsource(rowsource);
291   return NULL;
292 }
293