select.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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. #include <stdlib.h>
  15. #include <string.h>
  16. #include <grass/gis.h>
  17. #include <grass/dbmi.h>
  18. #include <grass/glocale.h>
  19. static int cmp(const void *pa, const void *pb)
  20. {
  21. int *p1 = (int *)pa;
  22. int *p2 = (int *)pb;
  23. if (*p1 < *p2)
  24. return -1;
  25. if (*p1 > *p2)
  26. return 1;
  27. return 0;
  28. }
  29. static int cmpcat(const void *pa, const void *pb)
  30. {
  31. dbCatVal *p1 = (dbCatVal *) pa;
  32. dbCatVal *p2 = (dbCatVal *) pb;
  33. if (p1->cat < p2->cat)
  34. return -1;
  35. if (p1->cat > p2->cat)
  36. return 1;
  37. return 0;
  38. }
  39. static int cmpcatkey(const void *pa, const void *pb)
  40. {
  41. int *p1 = (int *)pa;
  42. dbCatVal *p2 = (dbCatVal *) pb;
  43. if (*p1 < p2->cat)
  44. return -1;
  45. if (*p1 > p2->cat)
  46. return 1;
  47. return 0;
  48. }
  49. static int cmpvalueint(const void *pa, const void *pb)
  50. {
  51. dbCatVal *p1 = (dbCatVal *) pa;
  52. dbCatVal *p2 = (dbCatVal *) pb;
  53. if (p1->val.i < p2->val.i)
  54. return -1;
  55. if (p1->val.i > p2->val.i)
  56. return 1;
  57. return 0;
  58. }
  59. static int cmpvaluedouble(const void *pa, const void *pb)
  60. {
  61. dbCatVal *p1 = (dbCatVal *) pa;
  62. dbCatVal *p2 = (dbCatVal *) pb;
  63. if (p1->val.d < p2->val.d)
  64. return -1;
  65. if (p1->val.d > p2->val.d)
  66. return 1;
  67. return 0;
  68. }
  69. static int cmpvaluestring(const void *pa, const void *pb)
  70. {
  71. dbCatVal *const *a = pa;
  72. dbCatVal *const *b = pb;
  73. return strcmp((const char *)a, (const char *)b);
  74. }
  75. /*!
  76. \brief Select array of ordered integers from table/column
  77. \param driver DB driver
  78. \param tab table name
  79. \param col column name
  80. \param where where statement
  81. \param[out] pval array of ordered integer values
  82. \return number of selected values
  83. \return -1 on error
  84. */
  85. int db_select_int(dbDriver * driver, const char *tab, const char *col,
  86. const char *where, int **pval)
  87. {
  88. int type, more, alloc, count;
  89. int *val;
  90. char buf[1024];
  91. const char *sval;
  92. dbString stmt;
  93. dbCursor cursor;
  94. dbColumn *column;
  95. dbValue *value;
  96. dbTable *table;
  97. G_debug(3, "db_select_int()");
  98. /* allocate */
  99. alloc = 1000;
  100. val = (int *)G_malloc(alloc * sizeof(int));
  101. if (where == NULL || strlen(where) == 0)
  102. G_snprintf(buf, 1023, "SELECT %s FROM %s", col, tab);
  103. else
  104. G_snprintf(buf, 1023, "SELECT %s FROM %s WHERE %s", col, tab, where);
  105. G_debug(3, " SQL: %s", buf);
  106. db_init_string(&stmt);
  107. db_append_string(&stmt, buf);
  108. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  109. return (-1);
  110. table = db_get_cursor_table(&cursor);
  111. column = db_get_table_column(table, 0); /* first column */
  112. if (column == NULL) {
  113. return -1;
  114. }
  115. value = db_get_column_value(column);
  116. type = db_get_column_sqltype(column);
  117. type = db_sqltype_to_Ctype(type);
  118. /* fetch the data */
  119. count = 0;
  120. while (1) {
  121. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  122. return (-1);
  123. if (!more)
  124. break;
  125. if (count == alloc) {
  126. alloc += 1000;
  127. val = (int *)G_realloc(val, alloc * sizeof(int));
  128. }
  129. switch (type) {
  130. case (DB_C_TYPE_INT):
  131. val[count] = db_get_value_int(value);
  132. break;
  133. case (DB_C_TYPE_STRING):
  134. sval = db_get_value_string(value);
  135. val[count] = atoi(sval);
  136. break;
  137. case (DB_C_TYPE_DOUBLE):
  138. val[count] = (int)db_get_value_double(value);
  139. break;
  140. default:
  141. return (-1);
  142. }
  143. count++;
  144. }
  145. db_close_cursor(&cursor);
  146. db_free_string(&stmt);
  147. qsort((void *)val, count, sizeof(int), cmp);
  148. *pval = val;
  149. return (count);
  150. }
  151. /*!
  152. \brief Select one (first) value from table/column for key/id
  153. \param driver DB driver
  154. \param tab table name
  155. \param key key column name
  156. \param id identifier in key column
  157. \param col name of column to select the value from
  158. \param[out] val dbValue to store within
  159. \return number of selected values
  160. \return -1 on error
  161. */
  162. int db_select_value(dbDriver * driver, const char *tab, const char *key,
  163. int id, const char *col, dbValue * val)
  164. {
  165. int more, count;
  166. char buf[1024];
  167. dbString stmt;
  168. dbCursor cursor;
  169. dbColumn *column;
  170. dbValue *value;
  171. dbTable *table;
  172. G_zero(val, sizeof(dbValue));
  173. sprintf(buf, "SELECT %s FROM %s WHERE %s = %d\n", col, tab, key, id);
  174. db_init_string(&stmt);
  175. db_append_string(&stmt, buf);
  176. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  177. return (-1);
  178. table = db_get_cursor_table(&cursor);
  179. column = db_get_table_column(table, 0); /* first column */
  180. value = db_get_column_value(column);
  181. /* fetch the data */
  182. count = 0;
  183. while (1) {
  184. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  185. return (-1);
  186. if (!more)
  187. break;
  188. if (count == 0)
  189. db_copy_value(val, value);
  190. count++;
  191. }
  192. db_close_cursor(&cursor);
  193. db_free_string(&stmt);
  194. return (count);
  195. }
  196. /*!
  197. \brief Select pairs key/value to array, values are sorted by key (must be integer)
  198. \param driver DB driver
  199. \param tab table name
  200. \param key key column name
  201. \param col value column name
  202. \param[out] cvarr dbCatValArray to store within
  203. \return number of selected values
  204. \return -1 on error
  205. */
  206. int db_select_CatValArray(dbDriver * driver, const char *tab, const char *key,
  207. const char *col, const char *where,
  208. dbCatValArray * cvarr)
  209. {
  210. int i, type, more, nrows;
  211. char buf[1024];
  212. dbString stmt;
  213. dbCursor cursor;
  214. dbColumn *column;
  215. dbValue *value;
  216. dbTable *table;
  217. G_debug(3, "db_select_db_select_CatValArray ()");
  218. db_init_string(&stmt);
  219. sprintf(buf, "SELECT %s, %s FROM %s", key, col, tab);
  220. db_set_string(&stmt, buf);
  221. if (where != NULL && strlen(where) > 0) {
  222. db_append_string(&stmt, " WHERE ");
  223. db_append_string(&stmt, where);
  224. }
  225. G_debug(3, " SQL: %s", db_get_string(&stmt));
  226. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  227. return (-1);
  228. nrows = db_get_num_rows(&cursor);
  229. G_debug(3, " %d rows selected", nrows);
  230. if (nrows < 0)
  231. G_fatal_error(_("Unable select records from table <%s>"), tab);
  232. db_CatValArray_alloc(cvarr, nrows);
  233. table = db_get_cursor_table(&cursor);
  234. /* Check if key column is integer */
  235. column = db_get_table_column(table, 0);
  236. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  237. G_debug(3, " key type = %d", type);
  238. if (type != DB_C_TYPE_INT) {
  239. G_fatal_error("Key column type is not integer");
  240. }
  241. column = db_get_table_column(table, 1);
  242. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  243. G_debug(3, " col type = %d", type);
  244. /*
  245. if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
  246. G_fatal_error ( "Column type not supported by db_select_to_array()" );
  247. }
  248. */
  249. cvarr->ctype = type;
  250. /* fetch the data */
  251. for (i = 0; i < nrows; i++) {
  252. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  253. return (-1);
  254. column = db_get_table_column(table, 0); /* first column */
  255. value = db_get_column_value(column);
  256. cvarr->value[i].cat = db_get_value_int(value);
  257. column = db_get_table_column(table, 1);
  258. value = db_get_column_value(column);
  259. cvarr->value[i].isNull = value->isNull;
  260. switch (type) {
  261. case (DB_C_TYPE_INT):
  262. if (value->isNull)
  263. cvarr->value[i].val.i = 0;
  264. else
  265. cvarr->value[i].val.i = db_get_value_int(value);
  266. break;
  267. case (DB_C_TYPE_DOUBLE):
  268. if (value->isNull)
  269. cvarr->value[i].val.d = 0.0;
  270. else
  271. cvarr->value[i].val.d = db_get_value_double(value);
  272. break;
  273. case (DB_C_TYPE_STRING):
  274. cvarr->value[i].val.s = (dbString *) malloc(sizeof(dbString));
  275. db_init_string(cvarr->value[i].val.s);
  276. if (!(value->isNull))
  277. db_set_string(cvarr->value[i].val.s,
  278. db_get_value_string(value));
  279. break;
  280. case (DB_C_TYPE_DATETIME):
  281. cvarr->value[i].val.t =
  282. (dbDateTime *) calloc(1, sizeof(dbDateTime));
  283. if (!(value->isNull))
  284. memcpy(cvarr->value[i].val.t, &(value->t),
  285. sizeof(dbDateTime));
  286. break;
  287. default:
  288. return (-1);
  289. }
  290. }
  291. cvarr->n_values = nrows;
  292. db_close_cursor(&cursor);
  293. db_free_string(&stmt);
  294. db_CatValArray_sort(cvarr);
  295. return (nrows);
  296. }
  297. /*!
  298. \brief Sort key/value array by key
  299. \param[in,out] arr dbCatValArray (key/value array)
  300. */
  301. void db_CatValArray_sort(dbCatValArray * arr)
  302. {
  303. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpcat);
  304. }
  305. /*!
  306. \brief Sort key/value array by value
  307. \param[in,out] arr dbCatValArray (key/value array)
  308. \return DB_OK on success
  309. \return DB_FAILED on error
  310. */
  311. int db_CatValArray_sort_by_value(dbCatValArray * arr)
  312. {
  313. switch (arr->ctype) {
  314. case (DB_C_TYPE_INT):
  315. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  316. cmpvalueint);
  317. break;
  318. case (DB_C_TYPE_DOUBLE):
  319. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  320. cmpvaluedouble);
  321. break;
  322. case (DB_C_TYPE_STRING):
  323. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  324. cmpvaluestring);
  325. break;
  326. case (DB_C_TYPE_DATETIME): /* is cmpvaluestring right here ? */
  327. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  328. cmpvaluestring);
  329. break;
  330. default:
  331. return (DB_FAILED);
  332. }
  333. return (DB_OK);
  334. }
  335. /*!
  336. \brief Find value by key
  337. \param arr dbCatValArray (key/value array)
  338. \param key key value
  339. \param[out] cv dbCatVal structure (key/value) to store within
  340. \return DB_OK on success
  341. \return DB_FAILED on error
  342. */
  343. int db_CatValArray_get_value(dbCatValArray * arr, int key, dbCatVal ** cv)
  344. {
  345. dbCatVal *catval;
  346. catval =
  347. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  348. cmpcat);
  349. if (catval == NULL) {
  350. return DB_FAILED;
  351. }
  352. *cv = catval;
  353. return DB_OK;
  354. }
  355. /*!
  356. \brief Find value (integer) by key
  357. \param arr dbCatValArray (key/value array)
  358. \param key key value
  359. \param[out] val found value (integer)
  360. \return DB_OK on success
  361. \return DB_FAILED on error
  362. */
  363. int db_CatValArray_get_value_int(dbCatValArray * arr, int key, int *val)
  364. {
  365. dbCatVal *catval;
  366. catval =
  367. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  368. cmpcat);
  369. if (catval == NULL) {
  370. return DB_FAILED;
  371. }
  372. *val = catval->val.i;
  373. return DB_OK;
  374. }
  375. /*!
  376. \brief Find value (double) by key
  377. \param arr dbCatValArray (key/value array)
  378. \param key key value
  379. \param[out] val found value (double)
  380. \return DB_OK on success
  381. \return DB_FAILED on error
  382. */
  383. int db_CatValArray_get_value_double(dbCatValArray * arr, int key, double *val)
  384. {
  385. dbCatVal *catval;
  386. G_debug(3, "db_CatValArray_get_value_double(), key = %d", key);
  387. catval =
  388. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  389. cmpcatkey);
  390. if (catval == NULL) {
  391. return DB_FAILED;
  392. }
  393. *val = catval->val.d;
  394. return DB_OK;
  395. }