vrpRouting  0.3
vroom.c
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 File: vroom.c
3 
4 Copyright (c) 2021 pgRouting developers
6 
7 Function's developer:
8 Copyright (c) 2021 Ashish Kumar
10 ------
11 
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16 
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 
26  ********************************************************************PGR-GNU*/
27 
33 #include <assert.h>
34 #include <stdbool.h>
35 
37 #include <utils/array.h> // NOLINT [build/include_order]
38 
39 #include "catalog/pg_type.h"
40 #include "utils/lsyscache.h"
41 
42 #ifndef INT8ARRAYOID
43 #define INT8ARRAYOID 1016
44 #endif
45 
46 #include "c_common/debug_macro.h"
47 #include "c_common/e_report.h"
48 #include "c_common/time_msg.h"
49 
50 #include "c_types/vroom/vroom_rt.h"
55 
62 
64 
65 PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS);
67 
93 static
94 void
96  char *jobs_sql,
97  char *jobs_tws_sql,
98  char *shipments_sql,
99  char *shipments_tws_sql,
100  char *vehicles_sql,
101  char *breaks_sql,
102  char *breaks_tws_sql,
103  char *matrix_sql,
104 
105  int32_t exploration_level,
106  int32_t timeout,
107  int16_t fn,
108  bool is_plain,
109 
110  Vroom_rt **result_tuples,
111  size_t *result_count) {
112  clock_t start_loading = clock();
113  pgr_SPI_connect();
114 
115  (*result_tuples) = NULL;
116  (*result_count) = 0;
117 
118  Vroom_job_t *jobs = NULL;
119  size_t total_jobs = 0;
120  if (jobs_sql) {
121  get_vroom_jobs(jobs_sql, &jobs, &total_jobs, is_plain);
122  }
123 
124  Vroom_shipment_t *shipments = NULL;
125  size_t total_shipments = 0;
126  if (shipments_sql) {
127  get_vroom_shipments(shipments_sql, &shipments, &total_shipments, is_plain);
128  }
129 
130  if (total_jobs == 0 && total_shipments == 0) {
131  if (fn == 0) {
132  ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL and Shipments SQL query."),
133  errhint("%s, %s", jobs_sql, shipments_sql)));
134  } else if (fn == 1) {
135  ereport(WARNING, (errmsg("Insufficient data found on Jobs SQL query."),
136  errhint("%s", jobs_sql)));
137  } else if (fn == 2) {
138  ereport(WARNING, (errmsg("Insufficient data found on Shipments SQL query."),
139  errhint("%s", shipments_sql)));
140  }
141  (*result_count) = 0;
142  (*result_tuples) = NULL;
143  pgr_SPI_finish();
144  return;
145  }
146 
147  Vroom_time_window_t *jobs_tws = NULL;
148  size_t total_jobs_tws = 0;
149  if (jobs_tws_sql) {
150  get_vroom_time_windows(jobs_tws_sql, &jobs_tws, &total_jobs_tws,
151  is_plain);
152  }
153 
154  Vroom_time_window_t *shipments_tws = NULL;
155  size_t total_shipments_tws = 0;
156  if (shipments_tws_sql) {
157  get_vroom_shipments_time_windows(shipments_tws_sql, &shipments_tws,
158  &total_shipments_tws, is_plain);
159  }
160 
161  Vroom_vehicle_t *vehicles = NULL;
162  size_t total_vehicles = 0;
163  get_vroom_vehicles(vehicles_sql, &vehicles, &total_vehicles, is_plain);
164 
165  if (total_vehicles == 0) {
166  ereport(WARNING, (errmsg("Insufficient data found on Vehicles SQL query."),
167  errhint("%s", vehicles_sql)));
168  (*result_count) = 0;
169  (*result_tuples) = NULL;
170  pgr_SPI_finish();
171  return;
172  }
173 
174  Vroom_break_t *breaks = NULL;
175  size_t total_breaks = 0;
176  if (breaks_sql) {
177  get_vroom_breaks(breaks_sql, &breaks, &total_breaks, is_plain);
178  }
179 
180  Vroom_time_window_t *breaks_tws = NULL;
181  size_t total_breaks_tws = 0;
182  if (breaks_tws_sql) {
183  get_vroom_time_windows(breaks_tws_sql, &breaks_tws, &total_breaks_tws,
184  is_plain);
185  }
186 
187  Vroom_matrix_t *matrix_rows = NULL;
188  size_t total_matrix_rows = 0;
189  get_vroom_matrix(matrix_sql, &matrix_rows, &total_matrix_rows, is_plain);
190 
191  if (total_matrix_rows == 0) {
192  ereport(WARNING, (errmsg("Insufficient data found on Matrix SQL query."),
193  errhint("%s", matrix_sql)));
194  (*result_count) = 0;
195  (*result_tuples) = NULL;
196  pgr_SPI_finish();
197  return;
198  }
199 
200  clock_t start_t = clock();
201  char *log_msg = NULL;
202  char *notice_msg = NULL;
203  char *err_msg = NULL;
204 
205  int32_t loading_time = (int)((clock() - start_loading) / CLOCKS_PER_SEC) * 1000;
206 
207  do_vrp_vroom(
208  jobs, total_jobs,
209  jobs_tws, total_jobs_tws,
210  shipments, total_shipments,
211  shipments_tws, total_shipments_tws,
212  vehicles, total_vehicles,
213  breaks, total_breaks,
214  breaks_tws, total_breaks_tws,
215  matrix_rows, total_matrix_rows,
216 
217  exploration_level,
218  timeout,
219  loading_time,
220 
221  result_tuples,
222  result_count,
223 
224  &log_msg,
225  &notice_msg,
226  &err_msg);
227 
228  time_msg("processing vrp_vroom", start_t, clock());
229 
230  if (err_msg && (*result_tuples)) {
231  pfree(*result_tuples);
232  (*result_tuples) = NULL;
233  (*result_count) = 0;
234  }
235 
236  pgr_global_report(log_msg, notice_msg, err_msg);
237 
238  if (log_msg) pfree(log_msg);
239  if (notice_msg) pfree(notice_msg);
240  if (err_msg) pfree(err_msg);
241 
242  if (jobs) pfree(jobs);
243  if (shipments) pfree(shipments);
244  if (vehicles) pfree(vehicles);
245  if (matrix_rows) pfree(matrix_rows);
246 
247  pgr_SPI_finish();
248 }
249 
250 
255 PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS) {
256  FuncCallContext *funcctx;
257  TupleDesc tuple_desc;
258 
259  /**********************************************************************/
260  Vroom_rt *result_tuples = NULL;
261  size_t result_count = 0;
262  /**********************************************************************/
263 
264  if (SRF_IS_FIRSTCALL()) {
265  MemoryContext oldcontext;
266  funcctx = SRF_FIRSTCALL_INIT();
267  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
268 
269  /***********************************************************************
270  *
271  * _vrp_vroom(
272  * jobs_sql TEXT,
273  * jobs_time_windows_sql TEXT,
274  * shipments_sql TEXT,
275  * shipments_time_windows_sql TEXT,
276  * vehicles_sql TEXT,
277  * breaks_sql TEXT,
278  * breaks_time_windows_sql TEXT,
279  * matrix_sql TEXT,
280  * exploration_level INTEGER default 5,
281  * timeout INTEGER default -1,
282  * fn SMALLINT,
283  * is_plain BOOLEAN
284  * );
285  *
286  **********************************************************************/
287 
288  char *args[8];
289  for (int i = 0; i < 8; i++) {
290  if (PG_ARGISNULL(i)) {
291  args[i] = NULL;
292  } else {
293  args[i] = text_to_cstring(PG_GETARG_TEXT_P(i));
294  }
295  }
296 
297  int32_t exploration_level = PG_GETARG_INT32(8);
298  int32_t timeout = PG_GETARG_INT32(9);
299  int16_t fn = PG_GETARG_INT16(10);
300  bool is_plain = PG_GETARG_BOOL(11);
301 
302  // Verify that both jobs_sql and shipments_sql are not NULL
303  if (args[0] == NULL && args[2] == NULL) {
304  if (fn == 0) {
305  elog(ERROR, "Both Jobs SQL and Shipments NULL must not be NULL");
306  } else if (fn == 1) {
307  elog(ERROR, "Jobs SQL must not be NULL");
308  } else if (fn == 2) {
309  elog(ERROR, "Shipments SQL must not be NULL");
310  }
311  }
312 
313  if (args[4] == NULL) {
314  elog(ERROR, "Vehicles SQL must not be NULL");
315  }
316 
317  if (args[7] == NULL) {
318  elog(ERROR, "Matrix SQL must not be NULL");
319  }
320 
321  process(
322  args[0],
323  args[1],
324  args[2],
325  args[3],
326  args[4],
327  args[5],
328  args[6],
329  args[7],
330  exploration_level,
331  timeout,
332  fn,
333  is_plain,
334  &result_tuples,
335  &result_count);
336 
337  /**********************************************************************/
338 
339 
340 #if PGSQL_VERSION > 95
341  funcctx->max_calls = result_count;
342 #else
343  funcctx->max_calls = (uint32_t)result_count;
344 #endif
345  funcctx->user_fctx = result_tuples;
346  if (get_call_result_type(fcinfo, NULL, &tuple_desc)
347  != TYPEFUNC_COMPOSITE) {
348  ereport(ERROR,
349  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
350  errmsg("function returning record called in context "
351  "that cannot accept type record")));
352  }
353 
354  funcctx->tuple_desc = tuple_desc;
355  MemoryContextSwitchTo(oldcontext);
356  }
357 
358  funcctx = SRF_PERCALL_SETUP();
359  tuple_desc = funcctx->tuple_desc;
360  result_tuples = (Vroom_rt*) funcctx->user_fctx;
361 
362  if (funcctx->call_cntr < funcctx->max_calls) {
363  HeapTuple tuple;
364  Datum result;
365  Datum *values;
366  bool* nulls;
367  int16 typlen;
368  size_t call_cntr = funcctx->call_cntr;
369 
370  size_t num = 16;
371  values = palloc(num * sizeof(Datum));
372  nulls = palloc(num * sizeof(bool));
373 
374  size_t i;
375  for (i = 0; i < num; ++i) {
376  nulls[i] = false;
377  }
378 
379  size_t load_size = (size_t)result_tuples[call_cntr].load_size;
380  Datum* load = (Datum*) palloc(sizeof(Datum) * (size_t)load_size);
381 
382  for (i = 0; i < load_size; ++i) {
383  load[i] = Int64GetDatum(result_tuples[call_cntr].load[i]);
384  }
385 
386  bool typbyval;
387  char typalign;
388  get_typlenbyvalalign(INT8OID, &typlen, &typbyval, &typalign);
389  ArrayType* arrayType;
390  /*
391  https://doxygen.postgresql.org/arrayfuncs_8c.html
392  ArrayType* construct_array(
393  Datum* elems,
394  int nelems,
395  Oid elmtype, int elmlen, bool elmbyval, char elmalign
396  )
397  */
398  arrayType = construct_array(load, (int)load_size, INT8OID, typlen,
399  typbyval, typalign);
400  /*
401  void TupleDescInitEntry(
402  TupleDesc desc,
403  AttrNumber attributeNumber,
404  const char * attributeName,
405  Oid oidtypeid,
406  int32 typmod,
407  int attdim
408  )
409  */
410  TupleDescInitEntry(tuple_desc, (AttrNumber) 16, "load", INT8ARRAYOID, -1, 0);
411 
412  values[0] = Int64GetDatum(funcctx->call_cntr + 1);
413  values[1] = Int64GetDatum(result_tuples[call_cntr].vehicle_seq);
414  values[2] = Int64GetDatum(result_tuples[call_cntr].vehicle_id);
415  values[3] = CStringGetTextDatum(result_tuples[call_cntr].vehicle_data);
416  values[4] = Int64GetDatum(result_tuples[call_cntr].step_seq);
417  values[5] = Int32GetDatum(result_tuples[call_cntr].step_type);
418  values[6] = Int64GetDatum(result_tuples[call_cntr].task_id);
419  values[7] = Int64GetDatum(result_tuples[call_cntr].location_id);
420  values[8] = CStringGetTextDatum(result_tuples[call_cntr].task_data);
421  values[9] = Int32GetDatum(result_tuples[call_cntr].arrival_time);
422  values[10] = Int32GetDatum(result_tuples[call_cntr].travel_time);
423  values[11] = Int32GetDatum(result_tuples[call_cntr].setup_time);
424  values[12] = Int32GetDatum(result_tuples[call_cntr].service_time);
425  values[13] = Int32GetDatum(result_tuples[call_cntr].waiting_time);
426  values[14] = Int32GetDatum(result_tuples[call_cntr].departure_time);
427  values[15] = PointerGetDatum(arrayType);
428 
429  /**********************************************************************/
430 
431  tuple = heap_form_tuple(tuple_desc, values, nulls);
432  result = HeapTupleGetDatum(tuple);
433  SRF_RETURN_NEXT(funcctx, result);
434  } else {
435  SRF_RETURN_DONE(funcctx);
436  }
437 }
get_vroom_vehicles
void get_vroom_vehicles(char *sql, Vroom_vehicle_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM vehicles.
Definition: vroom/vehicles_input.c:237
time_windows_input.h
matrix_input.h
time_msg.h
postgres_connection.h
vroom_driver.h
pgr_SPI_connect
void pgr_SPI_connect(void)
Definition: postgres_connection.c:79
vroom_vehicle_t.h
pgr_SPI_finish
void pgr_SPI_finish(void)
Definition: postgres_connection.c:71
e_report.h
process
static void process(char *jobs_sql, char *jobs_tws_sql, char *shipments_sql, char *shipments_tws_sql, char *vehicles_sql, char *breaks_sql, char *breaks_tws_sql, char *matrix_sql, int32_t exploration_level, int32_t timeout, int16_t fn, bool is_plain, Vroom_rt **result_tuples, size_t *result_count)
Static function, loads the data from postgres to C types for further processing.
Definition: vroom.c:95
Vroom_time_window_t
Time window's attributes.
Definition: vroom_time_window_t.h:46
get_vroom_breaks
void get_vroom_breaks(char *sql, Vroom_break_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM breaks.
Definition: breaks_input.c:160
get_vroom_matrix
void get_vroom_matrix(char *sql, Vroom_matrix_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM matrix.
Definition: matrix_input.c:159
debug_macro.h
vehicles_input.h
get_vroom_shipments
void get_vroom_shipments(char *sql, Vroom_shipment_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM shipments.
Definition: shipments_input.c:216
get_vroom_shipments_time_windows
void get_vroom_shipments_time_windows(char *sql, Vroom_time_window_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM shipments time windows.
Definition: time_windows_input.c:239
Vroom_shipment_t
Vehicles's attributes.
Definition: vroom_shipment_t.h:56
vroom_job_t.h
vroom_matrix_t.h
PG_FUNCTION_INFO_V1
PG_FUNCTION_INFO_V1(_vrp_vroom)
vroom_rt.h
shipments_input.h
Vroom_break_t
Vehicle's break attributes.
Definition: vroom_break_t.h:46
Vroom_matrix_t
Matrix's attributes.
Definition: vroom_matrix_t.h:46
Vroom_job_t
Job's attributes.
Definition: vroom_job_t.h:54
get_vroom_time_windows
void get_vroom_time_windows(char *sql, Vroom_time_window_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM time windows.
Definition: time_windows_input.c:204
if
if(DOXYGEN_FOUND) configure_file($
Definition: doxygen/CMakeLists.txt:13
time_msg
void time_msg(char *msg, clock_t start_t, clock_t end_t)
Definition: time_msg.c:32
_vrp_vroom
PGDLLEXPORT Datum _vrp_vroom(PG_FUNCTION_ARGS)
Helps in converting postgres variables to C variables, and returns the result.
Definition: vroom.c:255
get_vroom_jobs
void get_vroom_jobs(char *sql, Vroom_job_t **rows, size_t *total_rows, bool is_plain)
Reads the VROOM jobs.
Definition: jobs_input.c:213
jobs_input.h
Vroom_vehicle_t
Vehicles's attributes.
Definition: vroom_vehicle_t.h:54
Vroom_rt
Solution's attributes.
Definition: vroom_rt.h:57
INT8ARRAYOID
#define INT8ARRAYOID
Definition: vroom.c:43
vroom_shipment_t.h
do_vrp_vroom
void do_vrp_vroom(Vroom_job_t *jobs, size_t total_jobs, Vroom_time_window_t *jobs_tws, size_t total_jobs_tws, Vroom_shipment_t *shipments, size_t total_shipments, Vroom_time_window_t *shipments_tws, size_t total_shipments_tws, Vroom_vehicle_t *vehicles, size_t total_vehicles, Vroom_break_t *breaks, size_t total_breaks, Vroom_time_window_t *breaks_tws, size_t total_breaks_tws, Vroom_matrix_t *matrix_rows, size_t total_matrix_rows, int32_t exploration_level, int32_t timeout, int32_t loading_time, Vroom_rt **return_tuples, size_t *return_count, char **log_msg, char **notice_msg, char **err_msg)
Performs exception handling and converts the results to postgres.
Definition: vroom_driver.cpp:84
pgr_global_report
void pgr_global_report(char *log, char *notice, char *err)
notice & error
Definition: e_report.c:30
breaks_input.h