GRASS 8 Programmer's Manual  8.5.0dev(2025)-c070206eb1
db/dbmi_client/select.c
Go to the documentation of this file.
1 /*!
2  * \file db/dbmi_client/select.c
3  *
4  * \brief DBMI Library (client) - select records from table
5  *
6  * (C) 1999-2008 by the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public
9  * License (>=v2). Read the file COPYING that comes with GRASS
10  * for details.
11  *
12  * \author Joel Jones (CERL/UIUC), Radim Blazek
13  */
14 
15 #include <stdlib.h>
16 #include <string.h>
17 #include <grass/gis.h>
18 #include <grass/dbmi.h>
19 #include <grass/glocale.h>
20 
21 static int cmp(const void *pa, const void *pb)
22 {
23  int *p1 = (int *)pa;
24  int *p2 = (int *)pb;
25 
26  if (*p1 < *p2)
27  return -1;
28  if (*p1 > *p2)
29  return 1;
30  return 0;
31 }
32 
33 static int cmpcat(const void *pa, const void *pb)
34 {
35  dbCatVal *p1 = (dbCatVal *)pa;
36  dbCatVal *p2 = (dbCatVal *)pb;
37 
38  if (p1->cat < p2->cat)
39  return -1;
40  if (p1->cat > p2->cat)
41  return 1;
42  return 0;
43 }
44 
45 static int cmpcatkey(const void *pa, const void *pb)
46 {
47  int *p1 = (int *)pa;
48  dbCatVal *p2 = (dbCatVal *)pb;
49 
50  if (*p1 < p2->cat)
51  return -1;
52  if (*p1 > p2->cat)
53  return 1;
54  return 0;
55 }
56 
57 static int cmpvalueint(const void *pa, const void *pb)
58 {
59  dbCatVal *p1 = (dbCatVal *)pa;
60  dbCatVal *p2 = (dbCatVal *)pb;
61 
62  if (p1->val.i < p2->val.i)
63  return -1;
64  if (p1->val.i > p2->val.i)
65  return 1;
66 
67  return 0;
68 }
69 
70 static int cmpvaluedouble(const void *pa, const void *pb)
71 {
72  dbCatVal *p1 = (dbCatVal *)pa;
73  dbCatVal *p2 = (dbCatVal *)pb;
74 
75  if (p1->val.d < p2->val.d)
76  return -1;
77  if (p1->val.d > p2->val.d)
78  return 1;
79 
80  return 0;
81 }
82 
83 static int cmpvaluestring(const void *pa, const void *pb)
84 {
85  dbCatVal *const *a = pa;
86  dbCatVal *const *b = pb;
87 
88  return strcmp((const char *)a, (const char *)b);
89 }
90 
91 /*!
92  \brief Select array of ordered integers from table/column
93 
94  \param driver DB driver
95  \param tab table name
96  \param col column name
97  \param where where statement
98  \param[out] pval array of ordered integer values
99 
100  \return number of selected values
101  \return -1 on error
102  */
103 int db_select_int(dbDriver *driver, const char *tab, const char *col,
104  const char *where, int **pval)
105 {
106  int type, more, alloc, count;
107  int *val;
108  char *buf = NULL;
109  const char *sval;
110  dbString stmt;
111  dbCursor cursor;
112  dbColumn *column;
113  dbValue *value;
114  dbTable *table;
115 
116  G_debug(3, "db_select_int()");
117 
118  if (col == NULL || strlen(col) == 0) {
119  G_warning(_("Missing column name"));
120  return -1;
121  }
122 
123  /* allocate */
124  alloc = 1000;
125  val = (int *)G_malloc(alloc * sizeof(int));
126 
127  if (where == NULL || strlen(where) == 0)
128  G_asprintf(&buf, "SELECT %s FROM %s", col, tab);
129  else
130  G_asprintf(&buf, "SELECT %s FROM %s WHERE %s", col, tab, where);
131 
132  G_debug(3, " SQL: %s", buf);
133 
134  db_init_string(&stmt);
135  db_set_string(&stmt, buf);
136  G_free(buf);
137 
138  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
139  return (-1);
140 
141  table = db_get_cursor_table(&cursor);
142  column = db_get_table_column(table, 0); /* first column */
143  if (column == NULL) {
144  return -1;
145  }
146  value = db_get_column_value(column);
147  type = db_get_column_sqltype(column);
148  type = db_sqltype_to_Ctype(type);
149 
150  /* fetch the data */
151  count = 0;
152  while (1) {
153  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
154  return (-1);
155 
156  if (!more)
157  break;
158 
159  if (count == alloc) {
160  alloc += 1000;
161  val = (int *)G_realloc(val, alloc * sizeof(int));
162  }
163 
164  switch (type) {
165  case (DB_C_TYPE_INT):
166  val[count] = db_get_value_int(value);
167  break;
168  case (DB_C_TYPE_STRING):
169  sval = db_get_value_string(value);
170  val[count] = atoi(sval);
171  break;
172  case (DB_C_TYPE_DOUBLE):
173  val[count] = (int)db_get_value_double(value);
174  break;
175  default:
176  return (-1);
177  }
178  count++;
179  }
180 
181  db_close_cursor(&cursor);
182  db_free_string(&stmt);
183 
184  qsort((void *)val, count, sizeof(int), cmp);
185 
186  *pval = val;
187 
188  return (count);
189 }
190 
191 /*!
192  \brief Select one (first) value from table/column for key/id
193 
194  \param driver DB driver
195  \param tab table name
196  \param key key column name
197  \param id identifier in key column
198  \param col name of column to select the value from
199  \param[out] val dbValue to store within
200 
201  \return number of selected values
202  \return -1 on error
203  */
204 int db_select_value(dbDriver *driver, const char *tab, const char *key, int id,
205  const char *col, dbValue *val)
206 {
207  int more, count;
208  char *buf = NULL;
209  dbString stmt;
210  dbCursor cursor;
211  dbColumn *column;
212  dbValue *value;
213  dbTable *table;
214 
215  if (key == NULL || strlen(key) == 0) {
216  G_warning(_("Missing key column name"));
217  return -1;
218  }
219 
220  if (col == NULL || strlen(col) == 0) {
221  G_warning(_("Missing column name"));
222  return -1;
223  }
224 
225  G_zero(val, sizeof(dbValue));
226  G_asprintf(&buf, "SELECT %s FROM %s WHERE %s = %d", col, tab, key, id);
227  db_init_string(&stmt);
228  db_set_string(&stmt, buf);
229  G_free(buf);
230 
231  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
232  return (-1);
233 
234  table = db_get_cursor_table(&cursor);
235  column = db_get_table_column(table, 0); /* first column */
236  value = db_get_column_value(column);
237 
238  /* fetch the data */
239  count = 0;
240  while (1) {
241  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
242  return (-1);
243 
244  if (!more)
245  break;
246  if (count == 0)
247  db_copy_value(val, value);
248  count++;
249  }
250  db_close_cursor(&cursor);
251  db_free_string(&stmt);
252 
253  return (count);
254 }
255 
256 /*!
257  \brief Select pairs key/value to array, values are sorted by key (must be
258  integer)
259 
260  \param driver DB driver
261  \param tab table name
262  \param key key column name
263  \param col value column name
264  \param where where statement
265  \param[out] cvarr dbCatValArray to store within
266 
267  \return number of selected values
268  \return -1 on error
269  */
270 int db_select_CatValArray(dbDriver *driver, const char *tab, const char *key,
271  const char *col, const char *where,
272  dbCatValArray *cvarr)
273 {
274  int i, type, more, nrows, ncols;
275  char *buf = NULL;
276  dbString stmt;
277  dbCursor cursor;
278  dbColumn *column;
279  dbValue *value;
280  dbTable *table;
281 
282  G_debug(3, "db_select_CatValArray ()");
283 
284  if (key == NULL || strlen(key) == 0) {
285  G_warning(_("Missing key column name"));
286  return -1;
287  }
288 
289  if (col == NULL || strlen(col) == 0) {
290  G_warning(_("Missing column name"));
291  return -1;
292  }
293  db_init_string(&stmt);
294 
295  if (strcmp(key, col) == 0) {
296  ncols = 1;
297  G_asprintf(&buf, "SELECT %s FROM %s", key, tab);
298  }
299  else {
300  ncols = 2;
301  G_asprintf(&buf, "SELECT %s, %s FROM %s", key, col, tab);
302  }
303  db_set_string(&stmt, buf);
304  G_free(buf);
305 
306  if (where != NULL && strlen(where) > 0) {
307  db_append_string(&stmt, " WHERE ");
308  db_append_string(&stmt, where);
309  }
310 
311  G_debug(3, " SQL: %s", db_get_string(&stmt));
312 
313  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
314  return (-1);
315 
316  nrows = db_get_num_rows(&cursor);
317  G_debug(3, " %d rows selected", nrows);
318  if (nrows < 0) {
319  G_warning(_("Unable select records from table <%s>"), tab);
320  db_close_cursor(&cursor);
321  db_free_string(&stmt);
322  return -1;
323  }
324 
325  db_CatValArray_alloc(cvarr, nrows);
326 
327  table = db_get_cursor_table(&cursor);
328 
329  /* Check if key column is integer */
330  column = db_get_table_column(table, 0);
332  G_debug(3, " key type = %d", type);
333 
334  if (type != DB_C_TYPE_INT) {
335  G_warning(_("Key column type is not integer"));
336  db_close_cursor(&cursor);
337  db_free_string(&stmt);
338  return -1;
339  }
340 
341  if (ncols == 2) {
342  column = db_get_table_column(table, 1);
344  G_debug(3, " col type = %d", type);
345 
346  /*
347  if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
348  G_fatal_error ( "Column type not supported by db_select_to_array()"
349  );
350  }
351  */
352  }
353  cvarr->ctype = type;
354 
355  /* fetch the data */
356  for (i = 0; i < nrows; i++) {
357  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
358  return (-1);
359 
360  column = db_get_table_column(table, 0); /* first column */
361  value = db_get_column_value(column);
362  cvarr->value[i].cat = db_get_value_int(value);
363 
364  if (ncols == 2) {
365  column = db_get_table_column(table, 1);
366  value = db_get_column_value(column);
367  }
368  cvarr->value[i].isNull = value->isNull;
369  switch (type) {
370  case (DB_C_TYPE_INT):
371  if (value->isNull)
372  cvarr->value[i].val.i = 0;
373  else
374  cvarr->value[i].val.i = db_get_value_int(value);
375  break;
376 
377  case (DB_C_TYPE_DOUBLE):
378  if (value->isNull)
379  cvarr->value[i].val.d = 0.0;
380  else
381  cvarr->value[i].val.d = db_get_value_double(value);
382  break;
383 
384  case (DB_C_TYPE_STRING):
385  cvarr->value[i].val.s = (dbString *)malloc(sizeof(dbString));
386  db_init_string(cvarr->value[i].val.s);
387 
388  if (!(value->isNull))
389  db_set_string(cvarr->value[i].val.s,
390  db_get_value_string(value));
391  break;
392 
393  case (DB_C_TYPE_DATETIME):
394  cvarr->value[i].val.t = (dbDateTime *)calloc(1, sizeof(dbDateTime));
395 
396  if (!(value->isNull))
397  memcpy(cvarr->value[i].val.t, &(value->t), sizeof(dbDateTime));
398  break;
399 
400  default:
401  return (-1);
402  }
403  }
404  cvarr->n_values = nrows;
405 
406  db_close_cursor(&cursor);
407  db_free_string(&stmt);
408 
409  db_CatValArray_sort(cvarr);
410 
411  return nrows;
412 }
413 
414 /*!
415  \brief Sort key/value array by key
416  \param[in,out] arr dbCatValArray (key/value array)
417  */
419 {
420  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpcat);
421 }
422 
423 /*!
424  \brief Sort key/value array by value
425 
426  \param[in,out] arr dbCatValArray (key/value array)
427 
428  \return DB_OK on success
429  \return DB_FAILED on error
430  */
432 {
433  switch (arr->ctype) {
434  case (DB_C_TYPE_INT):
435  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpvalueint);
436  break;
437  case (DB_C_TYPE_DOUBLE):
438  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
439  cmpvaluedouble);
440  break;
441  case (DB_C_TYPE_STRING):
442  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
443  cmpvaluestring);
444  break;
445  case (DB_C_TYPE_DATETIME): /* is cmpvaluestring right here ? */
446  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
447  cmpvaluestring);
448  break;
449  default:
450  return (DB_FAILED);
451  }
452 
453  return (DB_OK);
454 }
455 
456 /*!
457  \brief Find value by key
458 
459  \param arr dbCatValArray (key/value array)
460  \param key key value
461  \param[out] cv dbCatVal structure (key/value) to store within
462 
463  \return DB_OK on success
464  \return DB_FAILED on error
465  */
467 {
468  dbCatVal *catval;
469 
470  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
471  cmpcat);
472  if (catval == NULL) {
473  return DB_FAILED;
474  }
475 
476  *cv = catval;
477 
478  return DB_OK;
479 }
480 
481 /*!
482  \brief Find value (integer) by key
483 
484  \param arr dbCatValArray (key/value array)
485  \param key key value
486  \param[out] val found value (integer)
487 
488  \return DB_OK on success
489  \return DB_FAILED on error
490  */
491 int db_CatValArray_get_value_int(dbCatValArray *arr, int key, int *val)
492 {
493  dbCatVal *catval;
494 
495  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
496  cmpcat);
497  if (catval == NULL) {
498  return DB_FAILED;
499  }
500 
501  *val = catval->val.i;
502 
503  return DB_OK;
504 }
505 
506 /*!
507  \brief Find value (double) by key
508 
509  \param arr dbCatValArray (key/value array)
510  \param key key value
511  \param[out] val found value (double)
512 
513  \return DB_OK on success
514  \return DB_FAILED on error
515  */
516 int db_CatValArray_get_value_double(dbCatValArray *arr, int key, double *val)
517 {
518  dbCatVal *catval;
519 
520  G_debug(3, "db_CatValArray_get_value_double(), key = %d", key);
521 
522  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
523  cmpcatkey);
524  if (catval == NULL) {
525  return DB_FAILED;
526  }
527 
528  *val = catval->val.d;
529 
530  return DB_OK;
531 }
#define NULL
Definition: ccmath.h:32
int db_CatValArray_get_value_double(dbCatValArray *arr, int key, double *val)
Find value (double) by key.
int db_select_CatValArray(dbDriver *driver, const char *tab, const char *key, const char *col, const char *where, dbCatValArray *cvarr)
Select pairs key/value to array, values are sorted by key (must be integer)
int db_select_int(dbDriver *driver, const char *tab, const char *col, const char *where, int **pval)
Select array of ordered integers from table/column.
int db_select_value(dbDriver *driver, const char *tab, const char *key, int id, const char *col, dbValue *val)
Select one (first) value from table/column for key/id.
int db_CatValArray_get_value_int(dbCatValArray *arr, int key, int *val)
Find value (integer) by key.
void db_CatValArray_sort(dbCatValArray *arr)
Sort key/value array by key.
int db_CatValArray_sort_by_value(dbCatValArray *arr)
Sort key/value array by value.
int db_CatValArray_get_value(dbCatValArray *arr, int key, dbCatVal **cv)
Find value by key.
Main header of GRASS DataBase Management Interface.
struct _db_date_time dbDateTime
#define DB_C_TYPE_INT
Definition: dbmi.h:108
#define DB_SEQUENTIAL
Definition: dbmi.h:123
#define DB_FAILED
Definition: dbmi.h:72
#define DB_C_TYPE_STRING
Definition: dbmi.h:107
#define DB_C_TYPE_DOUBLE
Definition: dbmi.h:109
#define DB_OK
Definition: dbmi.h:71
#define DB_C_TYPE_DATETIME
Definition: dbmi.h:110
#define DB_NEXT
Definition: dbmi.h:114
void db_copy_value(dbValue *, dbValue *)
Copy value.
Definition: value.c:340
const char * db_get_value_string(dbValue *)
Get string value.
Definition: value.c:92
dbValue * db_get_column_value(dbColumn *)
Returns column value for given column structure.
dbColumn * db_get_table_column(dbTable *, int)
Returns column structure for given table and column number.
int db_CatValArray_alloc(dbCatValArray *, int)
Allocate dbCatValArray.
Definition: value.c:401
double db_get_value_double(dbValue *)
Get double precision value.
Definition: value.c:50
int db_sqltype_to_Ctype(int)
Get C data type based on given SQL data type.
Definition: sqlCtype.c:24
int db_get_column_sqltype(dbColumn *)
Returns column sqltype for column.
int db_get_num_rows(dbCursor *)
Get number of selected rows.
Definition: c_rows.c:26
dbTable * db_get_cursor_table(dbCursor *)
Get table allocated by cursor.
Definition: cursor.c:67
void db_free_string(dbString *)
Free allocated space for dbString.
Definition: string.c:150
int db_set_string(dbString *, const char *)
Inserts string to dbString (enlarge string)
Definition: string.c:41
int db_get_value_int(dbValue *)
Get integer value.
Definition: value.c:38
void db_init_string(dbString *)
Initialize dbString.
Definition: string.c:25
int db_close_cursor(dbCursor *)
Close cursor.
Definition: c_close_cur.c:27
int db_open_select_cursor(dbDriver *, dbString *, dbCursor *, int)
Open select cursor.
Definition: c_openselect.c:37
int db_append_string(dbString *, const char *)
Append string to dbString.
Definition: string.c:205
char * db_get_string(const dbString *)
Get string.
Definition: string.c:140
int db_fetch(dbCursor *, int, int *)
Fetch data from open cursor.
Definition: c_fetch.c:28
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition: gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:147
#define G_realloc(p, n)
Definition: defs/gis.h:96
void G_warning(const char *,...) __attribute__((format(printf
#define G_malloc(n)
Definition: defs/gis.h:94
int G_asprintf(char **, const char *,...) __attribute__((format(printf
int G_debug(int, const char *,...) __attribute__((format(printf
#define _(str)
Definition: glocale.h:10
int count
double b
Definition: r_raster.c:39
void * malloc(unsigned)
dbDateTime t
Definition: dbmi.h:192
char isNull
Definition: dbmi.h:188
int ctype
Definition: dbmi.h:272
int n_values
Definition: dbmi.h:270
dbCatVal * value
Definition: dbmi.h:273
Definition: dbmi.h:253
dbDateTime * t
Definition: dbmi.h:264
union dbCatVal::@1 val
int isNull
Definition: dbmi.h:255
int cat
Definition: dbmi.h:254
int i
Definition: dbmi.h:257
dbString * s
Definition: dbmi.h:263
double d
Definition: dbmi.h:258
Definition: driver.h:27