1 /*PGR-GNU*****************************************************************
2 File: contractGraph.c
3
4 Generated with Template by:
5 Copyright (c) 2015 pgRouting developers
6 Mail: project@pgrouting.org
7
8 Function's developer:
9 Copyright (c) 2016 Rohith Reddy
10 Mail:
11
12 ------
13
14 This program is free software; you can redistribute it and/or modify
15 it under the terms of the GNU General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27
28 ********************************************************************PGR-GNU*/
29
30 #include <stdbool.h>
31
32 #include "c_common/postgres_connection.h"
33 #include "utils/array.h"
34 #include "catalog/pg_type.h"
35 #include "utils/lsyscache.h"
36
37 #ifndef INT8ARRAYOID
38 #define INT8ARRAYOID 1016
39 #endif
40
41 #include "c_common/debug_macro.h"
42 #include "c_common/e_report.h"
43 #include "c_common/time_msg.h"
44 #include "c_types/contracted_rt.h"
45 #include "c_common/edges_input.h"
46 #include "c_common/arrays_input.h"
47 #include "drivers/contraction/contractGraph_driver.h"
48
49 PGDLLEXPORT Datum _pgr_contraction(PG_FUNCTION_ARGS);
50 PG_FUNCTION_INFO_V1(_pgr_contraction);
51
52
53 static
54 void
process(char * edges_sql,ArrayType * order,int num_cycles,ArrayType * forbidden,bool directed,contracted_rt ** result_tuples,size_t * result_count)55 process(char* edges_sql,
56 ArrayType* order,
57 int num_cycles,
58 ArrayType* forbidden,
59
60 bool directed,
61 contracted_rt **result_tuples,
62 size_t *result_count) {
63 /*
64 * nothing to do
65 */
66 if (num_cycles < 1) return;
67
68 pgr_SPI_connect();
69
70 size_t size_forbidden_vertices = 0;
71 int64_t* forbidden_vertices =
72 pgr_get_bigIntArray_allowEmpty(
73 &size_forbidden_vertices,
74 forbidden);
75 PGR_DBG("size_forbidden_vertices %ld", size_forbidden_vertices);
76
77 size_t size_contraction_order = 0;
78 int64_t* contraction_order =
79 pgr_get_bigIntArray(
80 &size_contraction_order,
81 order);
82 PGR_DBG("size_contraction_order %ld ", size_contraction_order);
83
84
85 size_t total_edges = 0;
86 pgr_edge_t* edges = NULL;
87 pgr_get_edges(edges_sql, &edges, &total_edges);
88 if (total_edges == 0) {
89 if (forbidden_vertices) pfree(forbidden_vertices);
90 if (contraction_order) pfree(contraction_order);
91 pgr_SPI_finish();
92 return;
93 }
94
95 PGR_DBG("Starting timer");
96 clock_t start_t = clock();
97 char* log_msg = NULL;
98 char* notice_msg = NULL;
99 char* err_msg = NULL;
100 do_pgr_contractGraph(
101 edges, total_edges,
102 forbidden_vertices, size_forbidden_vertices,
103 contraction_order, size_contraction_order,
104 num_cycles,
105 directed,
106 result_tuples, result_count,
107 &log_msg,
108 ¬ice_msg,
109 &err_msg);
110
111 time_msg("processing pgr_contraction()", start_t, clock());
112
113
114 if (err_msg && (*result_tuples)) {
115 pfree(*result_tuples);
116 (*result_tuples) = NULL;
117 (*result_count) = 0;
118 }
119
120 pgr_global_report(log_msg, notice_msg, err_msg);
121
122 if (log_msg) pfree(log_msg);
123 if (notice_msg) pfree(notice_msg);
124 if (err_msg) pfree(err_msg);
125 if (edges) pfree(edges);
126 if (forbidden_vertices) pfree(forbidden_vertices);
127 if (contraction_order) pfree(contraction_order);
128 pgr_SPI_finish();
129 }
130
131 PGDLLEXPORT Datum
_pgr_contraction(PG_FUNCTION_ARGS)132 _pgr_contraction(PG_FUNCTION_ARGS) {
133 FuncCallContext *funcctx;
134 TupleDesc tuple_desc;
135
136 /**********************************************************************/
137 contracted_rt *result_tuples = NULL;
138 size_t result_count = 0;
139 /**********************************************************************/
140
141 if (SRF_IS_FIRSTCALL()) {
142 MemoryContext oldcontext;
143 funcctx = SRF_FIRSTCALL_INIT();
144 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
145 /**********************************************************************/
146 /*
147 edges_sql TEXT,
148 contraction_order BIGINT[],
149 max_cycles integer DEFAULT 1,
150 forbidden_vertices BIGINT[] DEFAULT ARRAY[]::BIGINT[],
151 directed BOOLEAN DEFAULT true,
152
153 **********************************************************************/
154
155 process(
156 text_to_cstring(PG_GETARG_TEXT_P(0)),
157 PG_GETARG_ARRAYTYPE_P(1),
158 PG_GETARG_INT32(2),
159 PG_GETARG_ARRAYTYPE_P(3),
160 PG_GETARG_BOOL(4),
161 &result_tuples,
162 &result_count);
163
164
165 /**********************************************************************/
166 #if PGSQL_VERSION > 95
167 funcctx->max_calls = result_count;
168 #else
169 funcctx->max_calls = (uint32_t)result_count;
170 #endif
171 funcctx->user_fctx = result_tuples;
172 if (get_call_result_type(fcinfo, NULL, &tuple_desc)
173 != TYPEFUNC_COMPOSITE)
174 ereport(ERROR,
175 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
176 errmsg("function returning record called in context "
177 "that cannot accept type record")));
178 funcctx->tuple_desc = tuple_desc;
179 MemoryContextSwitchTo(oldcontext);
180 }
181
182 funcctx = SRF_PERCALL_SETUP();
183 tuple_desc = funcctx->tuple_desc;
184 result_tuples = (contracted_rt*) funcctx->user_fctx;
185
186 if (funcctx->call_cntr < funcctx->max_calls) {
187 HeapTuple tuple;
188 Datum result;
189 Datum *values;
190 bool *nulls;
191 int16 typlen;
192 size_t call_cntr = funcctx->call_cntr;
193
194 /**********************************************************************/
195 size_t numb = 6;
196 values =(Datum *)palloc(numb * sizeof(Datum));
197 nulls = palloc(numb * sizeof(bool));
198 size_t i;
199 for (i = 0; i < numb; ++i) {
200 nulls[i] = false;
201 }
202
203 size_t contracted_vertices_size =
204 (size_t)result_tuples[call_cntr].contracted_vertices_size;
205
206 Datum* contracted_vertices_array;
207 contracted_vertices_array = (Datum*) palloc(sizeof(Datum) *
208 (size_t)contracted_vertices_size);
209
210 for (i = 0; i < contracted_vertices_size; ++i) {
211 PGR_DBG("Storing contracted vertex %ld",
212 result_tuples[call_cntr].contracted_vertices[i]);
213 contracted_vertices_array[i] =
214 Int64GetDatum(result_tuples[call_cntr].contracted_vertices[i]);
215 }
216
217 bool typbyval;
218 char typalign;
219 get_typlenbyvalalign(INT8OID, &typlen, &typbyval, &typalign);
220 ArrayType* arrayType;
221 /*
222 * https://doxygen.postgresql.org/arrayfuncs_8c.html
223
224 ArrayType* construct_array(
225 Datum* elems,
226 int nelems,
227 Oid elmtype, int elmlen, bool elmbyval, char elmalign
228 )
229 */
230 arrayType = construct_array(
231 contracted_vertices_array,
232 (int)contracted_vertices_size,
233 INT8OID, typlen, typbyval, typalign);
234 /*
235 void TupleDescInitEntry(
236 TupleDesc desc,
237 AttrNumber attributeNumber,
238 const char * attributeName,
239 Oid oidtypeid,
240 int32 typmod,
241 int attdim
242 )
243 */
244 TupleDescInitEntry(tuple_desc, (AttrNumber) 3, "contracted_vertices",
245 INT8ARRAYOID, -1, 0);
246
247 values[0] = CStringGetTextDatum(result_tuples[call_cntr].type);
248 values[1] = Int64GetDatum(result_tuples[call_cntr].id);
249 values[2] = PointerGetDatum(arrayType);
250 values[3] = Int64GetDatum(result_tuples[call_cntr].source);
251 values[4] = Int64GetDatum(result_tuples[call_cntr].target);
252 values[5] = Float8GetDatum(result_tuples[call_cntr].cost);
253
254 /*********************************************************************/
255 tuple = heap_form_tuple(tuple_desc, values, nulls);
256 result = HeapTupleGetDatum(tuple);
257
258 /*
259 * cleaning up the contracted vertices array
260 */
261 if (result_tuples[funcctx->call_cntr].contracted_vertices) {
262 pfree(result_tuples[funcctx->call_cntr].contracted_vertices);
263 }
264 SRF_RETURN_NEXT(funcctx, result);
265 } else {
266 SRF_RETURN_DONE(funcctx);
267 }
268 }
269