GRASS 8 Programmer's Manual  8.5.0dev(2025)-2aa4836e38
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 
126  if (where == NULL || strlen(where) == 0)
127  G_asprintf(&buf, "SELECT %s FROM %s", col, tab);
128  else
129  G_asprintf(&buf, "SELECT %s FROM %s WHERE %s", col, tab, where);
130 
131  G_debug(3, " SQL: %s", buf);
132 
133  db_init_string(&stmt);
134  db_set_string(&stmt, buf);
135  G_free(buf);
136 
137  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
138  return (-1);
139 
140  table = db_get_cursor_table(&cursor);
141  column = db_get_table_column(table, 0); /* first column */
142  if (column == NULL) {
143  return -1;
144  }
145  value = db_get_column_value(column);
146  type = db_get_column_sqltype(column);
147  type = db_sqltype_to_Ctype(type);
148 
149  val = (int *)G_malloc(alloc * sizeof(int));
150  /* fetch the data */
151  count = 0;
152  while (1) {
153  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
154  G_free(val);
155  return (-1);
156  }
157 
158  if (!more)
159  break;
160 
161  if (count == alloc) {
162  alloc += 1000;
163  val = (int *)G_realloc(val, alloc * sizeof(int));
164  }
165 
166  switch (type) {
167  case (DB_C_TYPE_INT):
168  val[count] = db_get_value_int(value);
169  break;
170  case (DB_C_TYPE_STRING):
171  sval = db_get_value_string(value);
172  val[count] = atoi(sval);
173  break;
174  case (DB_C_TYPE_DOUBLE):
175  val[count] = (int)db_get_value_double(value);
176  break;
177  default:
178  G_free(val);
179  return (-1);
180  }
181  count++;
182  }
183 
184  db_close_cursor(&cursor);
185  db_free_string(&stmt);
186 
187  qsort((void *)val, count, sizeof(int), cmp);
188 
189  *pval = val;
190 
191  return (count);
192 }
193 
194 /*!
195  \brief Select one (first) value from table/column for key/id
196 
197  \param driver DB driver
198  \param tab table name
199  \param key key column name
200  \param id identifier in key column
201  \param col name of column to select the value from
202  \param[out] val dbValue to store within
203 
204  \return number of selected values
205  \return -1 on error
206  */
207 int db_select_value(dbDriver *driver, const char *tab, const char *key, int id,
208  const char *col, dbValue *val)
209 {
210  int more, count;
211  char *buf = NULL;
212  dbString stmt;
213  dbCursor cursor;
214  dbColumn *column;
215  dbValue *value;
216  dbTable *table;
217 
218  if (key == NULL || strlen(key) == 0) {
219  G_warning(_("Missing key column name"));
220  return -1;
221  }
222 
223  if (col == NULL || strlen(col) == 0) {
224  G_warning(_("Missing column name"));
225  return -1;
226  }
227 
228  G_zero(val, sizeof(dbValue));
229  G_asprintf(&buf, "SELECT %s FROM %s WHERE %s = %d", col, tab, key, id);
230  db_init_string(&stmt);
231  db_set_string(&stmt, buf);
232  G_free(buf);
233 
234  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
235  return (-1);
236 
237  table = db_get_cursor_table(&cursor);
238  column = db_get_table_column(table, 0); /* first column */
239  value = db_get_column_value(column);
240 
241  /* fetch the data */
242  count = 0;
243  while (1) {
244  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
245  return (-1);
246 
247  if (!more)
248  break;
249  if (count == 0)
250  db_copy_value(val, value);
251  count++;
252  }
253  db_close_cursor(&cursor);
254  db_free_string(&stmt);
255 
256  return (count);
257 }
258 
259 /*!
260  \brief Select pairs key/value to array, values are sorted by key (must be
261  integer)
262 
263  \param driver DB driver
264  \param tab table name
265  \param key key column name
266  \param col value column name
267  \param where where statement
268  \param[out] cvarr dbCatValArray to store within
269 
270  \return number of selected values
271  \return -1 on error
272  */
273 int db_select_CatValArray(dbDriver *driver, const char *tab, const char *key,
274  const char *col, const char *where,
275  dbCatValArray *cvarr)
276 {
277  int i, type, more, nrows, ncols;
278  char *buf = NULL;
279  dbString stmt;
280  dbCursor cursor;
281  dbColumn *column;
282  dbValue *value;
283  dbTable *table;
284 
285  G_debug(3, "db_select_CatValArray ()");
286 
287  if (key == NULL || strlen(key) == 0) {
288  G_warning(_("Missing key column name"));
289  return -1;
290  }
291 
292  if (col == NULL || strlen(col) == 0) {
293  G_warning(_("Missing column name"));
294  return -1;
295  }
296  db_init_string(&stmt);
297 
298  if (strcmp(key, col) == 0) {
299  ncols = 1;
300  G_asprintf(&buf, "SELECT %s FROM %s", key, tab);
301  }
302  else {
303  ncols = 2;
304  G_asprintf(&buf, "SELECT %s, %s FROM %s", key, col, tab);
305  }
306  db_set_string(&stmt, buf);
307  G_free(buf);
308 
309  if (where != NULL && strlen(where) > 0) {
310  db_append_string(&stmt, " WHERE ");
311  db_append_string(&stmt, where);
312  }
313 
314  G_debug(3, " SQL: %s", db_get_string(&stmt));
315 
316  if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
317  return (-1);
318 
319  nrows = db_get_num_rows(&cursor);
320  G_debug(3, " %d rows selected", nrows);
321  if (nrows < 0) {
322  G_warning(_("Unable select records from table <%s>"), tab);
323  db_close_cursor(&cursor);
324  db_free_string(&stmt);
325  return -1;
326  }
327 
328  db_CatValArray_alloc(cvarr, nrows);
329 
330  table = db_get_cursor_table(&cursor);
331 
332  /* Check if key column is integer */
333  column = db_get_table_column(table, 0);
335  G_debug(3, " key type = %d", type);
336 
337  if (type != DB_C_TYPE_INT) {
338  G_warning(_("Key column type is not integer"));
339  db_close_cursor(&cursor);
340  db_free_string(&stmt);
341  return -1;
342  }
343 
344  if (ncols == 2) {
345  column = db_get_table_column(table, 1);
347  G_debug(3, " col type = %d", type);
348 
349  /*
350  if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
351  G_fatal_error ( "Column type not supported by db_select_to_array()"
352  );
353  }
354  */
355  }
356  cvarr->ctype = type;
357 
358  /* fetch the data */
359  for (i = 0; i < nrows; i++) {
360  if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
361  return (-1);
362 
363  column = db_get_table_column(table, 0); /* first column */
364  value = db_get_column_value(column);
365  cvarr->value[i].cat = db_get_value_int(value);
366 
367  if (ncols == 2) {
368  column = db_get_table_column(table, 1);
369  value = db_get_column_value(column);
370  }
371  cvarr->value[i].isNull = value->isNull;
372  switch (type) {
373  case (DB_C_TYPE_INT):
374  if (value->isNull)
375  cvarr->value[i].val.i = 0;
376  else
377  cvarr->value[i].val.i = db_get_value_int(value);
378  break;
379 
380  case (DB_C_TYPE_DOUBLE):
381  if (value->isNull)
382  cvarr->value[i].val.d = 0.0;
383  else
384  cvarr->value[i].val.d = db_get_value_double(value);
385  break;
386 
387  case (DB_C_TYPE_STRING):
388  cvarr->value[i].val.s = (dbString *)malloc(sizeof(dbString));
389  db_init_string(cvarr->value[i].val.s);
390 
391  if (!(value->isNull))
392  db_set_string(cvarr->value[i].val.s,
393  db_get_value_string(value));
394  break;
395 
396  case (DB_C_TYPE_DATETIME):
397  cvarr->value[i].val.t = (dbDateTime *)calloc(1, sizeof(dbDateTime));
398 
399  if (!(value->isNull))
400  memcpy(cvarr->value[i].val.t, &(value->t), sizeof(dbDateTime));
401  break;
402 
403  default:
404  return (-1);
405  }
406  }
407  cvarr->n_values = nrows;
408 
409  db_close_cursor(&cursor);
410  db_free_string(&stmt);
411 
412  db_CatValArray_sort(cvarr);
413 
414  return nrows;
415 }
416 
417 /*!
418  \brief Sort key/value array by key
419  \param[in,out] arr dbCatValArray (key/value array)
420  */
422 {
423  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpcat);
424 }
425 
426 /*!
427  \brief Sort key/value array by value
428 
429  \param[in,out] arr dbCatValArray (key/value array)
430 
431  \return DB_OK on success
432  \return DB_FAILED on error
433  */
435 {
436  switch (arr->ctype) {
437  case (DB_C_TYPE_INT):
438  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpvalueint);
439  break;
440  case (DB_C_TYPE_DOUBLE):
441  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
442  cmpvaluedouble);
443  break;
444  case (DB_C_TYPE_STRING):
445  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
446  cmpvaluestring);
447  break;
448  case (DB_C_TYPE_DATETIME): /* is cmpvaluestring right here ? */
449  qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
450  cmpvaluestring);
451  break;
452  default:
453  return (DB_FAILED);
454  }
455 
456  return (DB_OK);
457 }
458 
459 /*!
460  \brief Find value by key
461 
462  \param arr dbCatValArray (key/value array)
463  \param key key value
464  \param[out] cv dbCatVal structure (key/value) to store within
465 
466  \return DB_OK on success
467  \return DB_FAILED on error
468  */
470 {
471  dbCatVal *catval;
472 
473  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
474  cmpcat);
475  if (catval == NULL) {
476  return DB_FAILED;
477  }
478 
479  *cv = catval;
480 
481  return DB_OK;
482 }
483 
484 /*!
485  \brief Find value (integer) by key
486 
487  \param arr dbCatValArray (key/value array)
488  \param key key value
489  \param[out] val found value (integer)
490 
491  \return DB_OK on success
492  \return DB_FAILED on error
493  */
494 int db_CatValArray_get_value_int(dbCatValArray *arr, int key, int *val)
495 {
496  dbCatVal *catval;
497 
498  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
499  cmpcat);
500  if (catval == NULL) {
501  return DB_FAILED;
502  }
503 
504  *val = catval->val.i;
505 
506  return DB_OK;
507 }
508 
509 /*!
510  \brief Find value (double) by key
511 
512  \param arr dbCatValArray (key/value array)
513  \param key key value
514  \param[out] val found value (double)
515 
516  \return DB_OK on success
517  \return DB_FAILED on error
518  */
519 int db_CatValArray_get_value_double(dbCatValArray *arr, int key, double *val)
520 {
521  dbCatVal *catval;
522 
523  G_debug(3, "db_CatValArray_get_value_double(), key = %d", key);
524 
525  catval = bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
526  cmpcatkey);
527  if (catval == NULL) {
528  return DB_FAILED;
529  }
530 
531  *val = catval->val.d;
532 
533  return DB_OK;
534 }
#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