select.c 12 KB

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