select.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  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. if (col == NULL || strlen(col) == 0) {
  99. G_warning(_("Missing column name"));
  100. return -1;
  101. }
  102. /* allocate */
  103. alloc = 1000;
  104. val = (int *)G_malloc(alloc * sizeof(int));
  105. if (where == NULL || strlen(where) == 0)
  106. G_snprintf(buf, 1023, "SELECT %s FROM %s", col, tab);
  107. else
  108. G_snprintf(buf, 1023, "SELECT %s FROM %s WHERE %s", col, tab, where);
  109. G_debug(3, " SQL: %s", buf);
  110. db_init_string(&stmt);
  111. db_append_string(&stmt, buf);
  112. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  113. return (-1);
  114. table = db_get_cursor_table(&cursor);
  115. column = db_get_table_column(table, 0); /* first column */
  116. if (column == NULL) {
  117. return -1;
  118. }
  119. value = db_get_column_value(column);
  120. type = db_get_column_sqltype(column);
  121. type = db_sqltype_to_Ctype(type);
  122. /* fetch the data */
  123. count = 0;
  124. while (1) {
  125. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  126. return (-1);
  127. if (!more)
  128. break;
  129. if (count == alloc) {
  130. alloc += 1000;
  131. val = (int *)G_realloc(val, alloc * sizeof(int));
  132. }
  133. switch (type) {
  134. case (DB_C_TYPE_INT):
  135. val[count] = db_get_value_int(value);
  136. break;
  137. case (DB_C_TYPE_STRING):
  138. sval = db_get_value_string(value);
  139. val[count] = atoi(sval);
  140. break;
  141. case (DB_C_TYPE_DOUBLE):
  142. val[count] = (int)db_get_value_double(value);
  143. break;
  144. default:
  145. return (-1);
  146. }
  147. count++;
  148. }
  149. db_close_cursor(&cursor);
  150. db_free_string(&stmt);
  151. qsort((void *)val, count, sizeof(int), cmp);
  152. *pval = val;
  153. return (count);
  154. }
  155. /*!
  156. \brief Select one (first) value from table/column for key/id
  157. \param driver DB driver
  158. \param tab table name
  159. \param key key column name
  160. \param id identifier in key column
  161. \param col name of column to select the value from
  162. \param[out] val dbValue to store within
  163. \return number of selected values
  164. \return -1 on error
  165. */
  166. int db_select_value(dbDriver * driver, const char *tab, const char *key,
  167. int id, const char *col, dbValue * val)
  168. {
  169. int more, count;
  170. char buf[1024];
  171. dbString stmt;
  172. dbCursor cursor;
  173. dbColumn *column;
  174. dbValue *value;
  175. dbTable *table;
  176. if (key == NULL || strlen(key) == 0) {
  177. G_warning(_("Missing key column name"));
  178. return -1;
  179. }
  180. if (col == NULL || strlen(col) == 0) {
  181. G_warning(_("Missing column name"));
  182. return -1;
  183. }
  184. G_zero(val, sizeof(dbValue));
  185. sprintf(buf, "SELECT %s FROM %s WHERE %s = %d\n", col, tab, key, id);
  186. db_init_string(&stmt);
  187. db_append_string(&stmt, buf);
  188. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  189. return (-1);
  190. table = db_get_cursor_table(&cursor);
  191. column = db_get_table_column(table, 0); /* first column */
  192. value = db_get_column_value(column);
  193. /* fetch the data */
  194. count = 0;
  195. while (1) {
  196. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  197. return (-1);
  198. if (!more)
  199. break;
  200. if (count == 0)
  201. db_copy_value(val, value);
  202. count++;
  203. }
  204. db_close_cursor(&cursor);
  205. db_free_string(&stmt);
  206. return (count);
  207. }
  208. /*!
  209. \brief Select pairs key/value to array, values are sorted by key (must be integer)
  210. \param driver DB driver
  211. \param tab table name
  212. \param key key column name
  213. \param col value column name
  214. \param[out] cvarr dbCatValArray to store within
  215. \return number of selected values
  216. \return -1 on error
  217. */
  218. int db_select_CatValArray(dbDriver * driver, const char *tab, const char *key,
  219. const char *col, const char *where,
  220. dbCatValArray * cvarr)
  221. {
  222. int i, type, more, nrows;
  223. char buf[1024];
  224. dbString stmt;
  225. dbCursor cursor;
  226. dbColumn *column;
  227. dbValue *value;
  228. dbTable *table;
  229. G_debug(3, "db_select_CatValArray ()");
  230. if (key == NULL || strlen(key) == 0) {
  231. G_warning(_("Missing key column name"));
  232. return -1;
  233. }
  234. if (col == NULL || strlen(col) == 0) {
  235. G_warning(_("Missing column name"));
  236. return -1;
  237. }
  238. db_init_string(&stmt);
  239. sprintf(buf, "SELECT %s, %s FROM %s", key, col, tab);
  240. db_set_string(&stmt, buf);
  241. if (where != NULL && strlen(where) > 0) {
  242. db_append_string(&stmt, " WHERE ");
  243. db_append_string(&stmt, where);
  244. }
  245. G_debug(3, " SQL: %s", db_get_string(&stmt));
  246. if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
  247. return (-1);
  248. nrows = db_get_num_rows(&cursor);
  249. G_debug(3, " %d rows selected", nrows);
  250. if (nrows < 0) {
  251. G_warning(_("Unable select records from table <%s>"), tab);
  252. db_close_cursor(&cursor);
  253. db_free_string(&stmt);
  254. return -1;
  255. }
  256. db_CatValArray_alloc(cvarr, nrows);
  257. table = db_get_cursor_table(&cursor);
  258. /* Check if key column is integer */
  259. column = db_get_table_column(table, 0);
  260. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  261. G_debug(3, " key type = %d", type);
  262. if (type != DB_C_TYPE_INT) {
  263. G_warning(_("Key column type is not integer"));
  264. db_close_cursor(&cursor);
  265. db_free_string(&stmt);
  266. return -1;
  267. }
  268. column = db_get_table_column(table, 1);
  269. type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
  270. G_debug(3, " col type = %d", type);
  271. /*
  272. if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
  273. G_fatal_error ( "Column type not supported by db_select_to_array()" );
  274. }
  275. */
  276. cvarr->ctype = type;
  277. /* fetch the data */
  278. for (i = 0; i < nrows; i++) {
  279. if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
  280. return (-1);
  281. column = db_get_table_column(table, 0); /* first column */
  282. value = db_get_column_value(column);
  283. cvarr->value[i].cat = db_get_value_int(value);
  284. column = db_get_table_column(table, 1);
  285. value = db_get_column_value(column);
  286. cvarr->value[i].isNull = value->isNull;
  287. switch (type) {
  288. case (DB_C_TYPE_INT):
  289. if (value->isNull)
  290. cvarr->value[i].val.i = 0;
  291. else
  292. cvarr->value[i].val.i = db_get_value_int(value);
  293. break;
  294. case (DB_C_TYPE_DOUBLE):
  295. if (value->isNull)
  296. cvarr->value[i].val.d = 0.0;
  297. else
  298. cvarr->value[i].val.d = db_get_value_double(value);
  299. break;
  300. case (DB_C_TYPE_STRING):
  301. cvarr->value[i].val.s = (dbString *) malloc(sizeof(dbString));
  302. db_init_string(cvarr->value[i].val.s);
  303. if (!(value->isNull))
  304. db_set_string(cvarr->value[i].val.s,
  305. db_get_value_string(value));
  306. break;
  307. case (DB_C_TYPE_DATETIME):
  308. cvarr->value[i].val.t =
  309. (dbDateTime *) calloc(1, sizeof(dbDateTime));
  310. if (!(value->isNull))
  311. memcpy(cvarr->value[i].val.t, &(value->t),
  312. sizeof(dbDateTime));
  313. break;
  314. default:
  315. return (-1);
  316. }
  317. }
  318. cvarr->n_values = nrows;
  319. db_close_cursor(&cursor);
  320. db_free_string(&stmt);
  321. db_CatValArray_sort(cvarr);
  322. return (nrows);
  323. }
  324. /*!
  325. \brief Sort key/value array by key
  326. \param[in,out] arr dbCatValArray (key/value array)
  327. */
  328. void db_CatValArray_sort(dbCatValArray * arr)
  329. {
  330. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpcat);
  331. }
  332. /*!
  333. \brief Sort key/value array by value
  334. \param[in,out] arr dbCatValArray (key/value array)
  335. \return DB_OK on success
  336. \return DB_FAILED on error
  337. */
  338. int db_CatValArray_sort_by_value(dbCatValArray * arr)
  339. {
  340. switch (arr->ctype) {
  341. case (DB_C_TYPE_INT):
  342. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  343. cmpvalueint);
  344. break;
  345. case (DB_C_TYPE_DOUBLE):
  346. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  347. cmpvaluedouble);
  348. break;
  349. case (DB_C_TYPE_STRING):
  350. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  351. cmpvaluestring);
  352. break;
  353. case (DB_C_TYPE_DATETIME): /* is cmpvaluestring right here ? */
  354. qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
  355. cmpvaluestring);
  356. break;
  357. default:
  358. return (DB_FAILED);
  359. }
  360. return (DB_OK);
  361. }
  362. /*!
  363. \brief Find value by key
  364. \param arr dbCatValArray (key/value array)
  365. \param key key value
  366. \param[out] cv dbCatVal structure (key/value) to store within
  367. \return DB_OK on success
  368. \return DB_FAILED on error
  369. */
  370. int db_CatValArray_get_value(dbCatValArray * arr, int key, dbCatVal ** cv)
  371. {
  372. dbCatVal *catval;
  373. catval =
  374. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  375. cmpcat);
  376. if (catval == NULL) {
  377. return DB_FAILED;
  378. }
  379. *cv = catval;
  380. return DB_OK;
  381. }
  382. /*!
  383. \brief Find value (integer) by key
  384. \param arr dbCatValArray (key/value array)
  385. \param key key value
  386. \param[out] val found value (integer)
  387. \return DB_OK on success
  388. \return DB_FAILED on error
  389. */
  390. int db_CatValArray_get_value_int(dbCatValArray * arr, int key, int *val)
  391. {
  392. dbCatVal *catval;
  393. catval =
  394. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  395. cmpcat);
  396. if (catval == NULL) {
  397. return DB_FAILED;
  398. }
  399. *val = catval->val.i;
  400. return DB_OK;
  401. }
  402. /*!
  403. \brief Find value (double) by key
  404. \param arr dbCatValArray (key/value array)
  405. \param key key value
  406. \param[out] val found value (double)
  407. \return DB_OK on success
  408. \return DB_FAILED on error
  409. */
  410. int db_CatValArray_get_value_double(dbCatValArray * arr, int key, double *val)
  411. {
  412. dbCatVal *catval;
  413. G_debug(3, "db_CatValArray_get_value_double(), key = %d", key);
  414. catval =
  415. bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
  416. cmpcatkey);
  417. if (catval == NULL) {
  418. return DB_FAILED;
  419. }
  420. *val = catval->val.d;
  421. return DB_OK;
  422. }