123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535 |
- /*!
- * \file db/dbmi_client/select.c
- *
- * \brief DBMI Library (client) - select records from table
- *
- * (C) 1999-2008 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- * \author Joel Jones (CERL/UIUC), Radim Blazek
- */
- #include <stdlib.h>
- #include <string.h>
- #include <grass/gis.h>
- #include <grass/dbmi.h>
- #include <grass/glocale.h>
- static int cmp(const void *pa, const void *pb)
- {
- int *p1 = (int *)pa;
- int *p2 = (int *)pb;
- if (*p1 < *p2)
- return -1;
- if (*p1 > *p2)
- return 1;
- return 0;
- }
- static int cmpcat(const void *pa, const void *pb)
- {
- dbCatVal *p1 = (dbCatVal *) pa;
- dbCatVal *p2 = (dbCatVal *) pb;
- if (p1->cat < p2->cat)
- return -1;
- if (p1->cat > p2->cat)
- return 1;
- return 0;
- }
- static int cmpcatkey(const void *pa, const void *pb)
- {
- int *p1 = (int *)pa;
- dbCatVal *p2 = (dbCatVal *) pb;
- if (*p1 < p2->cat)
- return -1;
- if (*p1 > p2->cat)
- return 1;
- return 0;
- }
- static int cmpvalueint(const void *pa, const void *pb)
- {
- dbCatVal *p1 = (dbCatVal *) pa;
- dbCatVal *p2 = (dbCatVal *) pb;
- if (p1->val.i < p2->val.i)
- return -1;
- if (p1->val.i > p2->val.i)
- return 1;
- return 0;
- }
- static int cmpvaluedouble(const void *pa, const void *pb)
- {
- dbCatVal *p1 = (dbCatVal *) pa;
- dbCatVal *p2 = (dbCatVal *) pb;
- if (p1->val.d < p2->val.d)
- return -1;
- if (p1->val.d > p2->val.d)
- return 1;
- return 0;
- }
- static int cmpvaluestring(const void *pa, const void *pb)
- {
- dbCatVal *const *a = pa;
- dbCatVal *const *b = pb;
- return strcmp((const char *)a, (const char *)b);
- }
- /*!
- \brief Select array of ordered integers from table/column
- \param driver DB driver
- \param tab table name
- \param col column name
- \param where where statement
- \param[out] pval array of ordered integer values
- \return number of selected values
- \return -1 on error
- */
- int db_select_int(dbDriver * driver, const char *tab, const char *col,
- const char *where, int **pval)
- {
- int type, more, alloc, count;
- int *val;
- char *buf = NULL;
- const char *sval;
- dbString stmt;
- dbCursor cursor;
- dbColumn *column;
- dbValue *value;
- dbTable *table;
- G_debug(3, "db_select_int()");
- if (col == NULL || strlen(col) == 0) {
- G_warning(_("Missing column name"));
- return -1;
- }
- /* allocate */
- alloc = 1000;
- val = (int *)G_malloc(alloc * sizeof(int));
- if (where == NULL || strlen(where) == 0)
- G_asprintf(&buf, "SELECT %s FROM %s", col, tab);
- else
- G_asprintf(&buf, "SELECT %s FROM %s WHERE %s", col, tab, where);
- G_debug(3, " SQL: %s", buf);
- db_init_string(&stmt);
- db_set_string(&stmt, buf);
- G_free(buf);
- if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
- return (-1);
- table = db_get_cursor_table(&cursor);
- column = db_get_table_column(table, 0); /* first column */
- if (column == NULL) {
- return -1;
- }
- value = db_get_column_value(column);
- type = db_get_column_sqltype(column);
- type = db_sqltype_to_Ctype(type);
- /* fetch the data */
- count = 0;
- while (1) {
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
- return (-1);
- if (!more)
- break;
- if (count == alloc) {
- alloc += 1000;
- val = (int *)G_realloc(val, alloc * sizeof(int));
- }
- switch (type) {
- case (DB_C_TYPE_INT):
- val[count] = db_get_value_int(value);
- break;
- case (DB_C_TYPE_STRING):
- sval = db_get_value_string(value);
- val[count] = atoi(sval);
- break;
- case (DB_C_TYPE_DOUBLE):
- val[count] = (int)db_get_value_double(value);
- break;
- default:
- return (-1);
- }
- count++;
- }
- db_close_cursor(&cursor);
- db_free_string(&stmt);
- qsort((void *)val, count, sizeof(int), cmp);
- *pval = val;
- return (count);
- }
- /*!
- \brief Select one (first) value from table/column for key/id
- \param driver DB driver
- \param tab table name
- \param key key column name
- \param id identifier in key column
- \param col name of column to select the value from
- \param[out] val dbValue to store within
- \return number of selected values
- \return -1 on error
- */
- int db_select_value(dbDriver * driver, const char *tab, const char *key,
- int id, const char *col, dbValue * val)
- {
- int more, count;
- char *buf = NULL;
- dbString stmt;
- dbCursor cursor;
- dbColumn *column;
- dbValue *value;
- dbTable *table;
- if (key == NULL || strlen(key) == 0) {
- G_warning(_("Missing key column name"));
- return -1;
- }
- if (col == NULL || strlen(col) == 0) {
- G_warning(_("Missing column name"));
- return -1;
- }
- G_zero(val, sizeof(dbValue));
- G_asprintf(&buf, "SELECT %s FROM %s WHERE %s = %d", col, tab, key, id);
- db_init_string(&stmt);
- db_set_string(&stmt, buf);
- G_free(buf);
- if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
- return (-1);
- table = db_get_cursor_table(&cursor);
- column = db_get_table_column(table, 0); /* first column */
- value = db_get_column_value(column);
- /* fetch the data */
- count = 0;
- while (1) {
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
- return (-1);
- if (!more)
- break;
- if (count == 0)
- db_copy_value(val, value);
- count++;
- }
- db_close_cursor(&cursor);
- db_free_string(&stmt);
- return (count);
- }
- /*!
- \brief Select pairs key/value to array, values are sorted by key (must be integer)
- \param driver DB driver
- \param tab table name
- \param key key column name
- \param col value column name
- \param[out] cvarr dbCatValArray to store within
- \return number of selected values
- \return -1 on error
- */
- int db_select_CatValArray(dbDriver * driver, const char *tab, const char *key,
- const char *col, const char *where,
- dbCatValArray * cvarr)
- {
- int i, type, more, nrows, ncols;
- char *buf = NULL;
- dbString stmt;
- dbCursor cursor;
- dbColumn *column;
- dbValue *value;
- dbTable *table;
- G_debug(3, "db_select_CatValArray ()");
- if (key == NULL || strlen(key) == 0) {
- G_warning(_("Missing key column name"));
- return -1;
- }
- if (col == NULL || strlen(col) == 0) {
- G_warning(_("Missing column name"));
- return -1;
- }
- db_init_string(&stmt);
- if (strcmp(key, col) == 0) {
- ncols = 1;
- G_asprintf(&buf, "SELECT %s FROM %s", key, tab);
- }
- else {
- ncols = 2;
- G_asprintf(&buf, "SELECT %s, %s FROM %s", key, col, tab);
- }
- db_set_string(&stmt, buf);
- G_free(buf);
- if (where != NULL && strlen(where) > 0) {
- db_append_string(&stmt, " WHERE ");
- db_append_string(&stmt, where);
- }
- G_debug(3, " SQL: %s", db_get_string(&stmt));
- if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
- return (-1);
- nrows = db_get_num_rows(&cursor);
- G_debug(3, " %d rows selected", nrows);
- if (nrows < 0) {
- G_warning(_("Unable select records from table <%s>"), tab);
- db_close_cursor(&cursor);
- db_free_string(&stmt);
- return -1;
- }
- db_CatValArray_alloc(cvarr, nrows);
- table = db_get_cursor_table(&cursor);
- /* Check if key column is integer */
- column = db_get_table_column(table, 0);
- type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
- G_debug(3, " key type = %d", type);
- if (type != DB_C_TYPE_INT) {
- G_warning(_("Key column type is not integer"));
- db_close_cursor(&cursor);
- db_free_string(&stmt);
- return -1;
- }
- if (ncols == 2) {
- column = db_get_table_column(table, 1);
- type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
- G_debug(3, " col type = %d", type);
- /*
- if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
- G_fatal_error ( "Column type not supported by db_select_to_array()" );
- }
- */
- }
- cvarr->ctype = type;
- /* fetch the data */
- for (i = 0; i < nrows; i++) {
- if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
- return (-1);
- column = db_get_table_column(table, 0); /* first column */
- value = db_get_column_value(column);
- cvarr->value[i].cat = db_get_value_int(value);
- if (ncols == 2) {
- column = db_get_table_column(table, 1);
- value = db_get_column_value(column);
- }
- cvarr->value[i].isNull = value->isNull;
- switch (type) {
- case (DB_C_TYPE_INT):
- if (value->isNull)
- cvarr->value[i].val.i = 0;
- else
- cvarr->value[i].val.i = db_get_value_int(value);
- break;
- case (DB_C_TYPE_DOUBLE):
- if (value->isNull)
- cvarr->value[i].val.d = 0.0;
- else
- cvarr->value[i].val.d = db_get_value_double(value);
- break;
- case (DB_C_TYPE_STRING):
- cvarr->value[i].val.s = (dbString *) malloc(sizeof(dbString));
- db_init_string(cvarr->value[i].val.s);
- if (!(value->isNull))
- db_set_string(cvarr->value[i].val.s,
- db_get_value_string(value));
- break;
- case (DB_C_TYPE_DATETIME):
- cvarr->value[i].val.t =
- (dbDateTime *) calloc(1, sizeof(dbDateTime));
- if (!(value->isNull))
- memcpy(cvarr->value[i].val.t, &(value->t),
- sizeof(dbDateTime));
- break;
- default:
- return (-1);
- }
- }
- cvarr->n_values = nrows;
- db_close_cursor(&cursor);
- db_free_string(&stmt);
- db_CatValArray_sort(cvarr);
- return nrows;
- }
- /*!
- \brief Sort key/value array by key
- \param[in,out] arr dbCatValArray (key/value array)
- */
- void db_CatValArray_sort(dbCatValArray * arr)
- {
- qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal), cmpcat);
- }
- /*!
- \brief Sort key/value array by value
-
- \param[in,out] arr dbCatValArray (key/value array)
-
- \return DB_OK on success
- \return DB_FAILED on error
- */
- int db_CatValArray_sort_by_value(dbCatValArray * arr)
- {
- switch (arr->ctype) {
- case (DB_C_TYPE_INT):
- qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
- cmpvalueint);
- break;
- case (DB_C_TYPE_DOUBLE):
- qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
- cmpvaluedouble);
- break;
- case (DB_C_TYPE_STRING):
- qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
- cmpvaluestring);
- break;
- case (DB_C_TYPE_DATETIME): /* is cmpvaluestring right here ? */
- qsort((void *)arr->value, arr->n_values, sizeof(dbCatVal),
- cmpvaluestring);
- break;
- default:
- return (DB_FAILED);
- }
- return (DB_OK);
- }
- /*!
- \brief Find value by key
- \param arr dbCatValArray (key/value array)
- \param key key value
- \param[out] cv dbCatVal structure (key/value) to store within
- \return DB_OK on success
- \return DB_FAILED on error
- */
- int db_CatValArray_get_value(dbCatValArray * arr, int key, dbCatVal ** cv)
- {
- dbCatVal *catval;
- catval =
- bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
- cmpcat);
- if (catval == NULL) {
- return DB_FAILED;
- }
- *cv = catval;
- return DB_OK;
- }
- /*!
- \brief Find value (integer) by key
- \param arr dbCatValArray (key/value array)
- \param key key value
- \param[out] val found value (integer)
- \return DB_OK on success
- \return DB_FAILED on error
- */
- int db_CatValArray_get_value_int(dbCatValArray * arr, int key, int *val)
- {
- dbCatVal *catval;
- catval =
- bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
- cmpcat);
- if (catval == NULL) {
- return DB_FAILED;
- }
- *val = catval->val.i;
- return DB_OK;
- }
- /*!
- \brief Find value (double) by key
-
- \param arr dbCatValArray (key/value array)
- \param key key value
- \param[out] val found value (double)
- \return DB_OK on success
- \return DB_FAILED on error
- */
- int db_CatValArray_get_value_double(dbCatValArray * arr, int key, double *val)
- {
- dbCatVal *catval;
- G_debug(3, "db_CatValArray_get_value_double(), key = %d", key);
- catval =
- bsearch((void *)&key, arr->value, arr->n_values, sizeof(dbCatVal),
- cmpcatkey);
- if (catval == NULL) {
- return DB_FAILED;
- }
- *val = catval->val.d;
- return DB_OK;
- }
|