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