00001
00024 #include <stdlib.h>
00025 #include <stdio.h>
00026 #include <string.h>
00027 #include <grass/glocale.h>
00028 #include <grass/gis.h>
00029 #include <grass/dbmi.h>
00030 #include <grass/Vect.h>
00031
00032 #include <gdal_version.h>
00033
00034 #ifdef HAVE_OGR
00035 #include <ogr_api.h>
00036 #endif
00037
00045 struct dblinks *Vect_new_dblinks_struct(void)
00046 {
00047 struct dblinks *p;
00048
00049 p = (struct dblinks *)G_malloc(sizeof(struct dblinks));
00050
00051 if (p) {
00052 p->alloc_fields = p->n_fields = 0;
00053 p->field = NULL;
00054 }
00055
00056 return p;
00057 }
00058
00066 void Vect_reset_dblinks(struct dblinks *p)
00067 {
00068 p->n_fields = 0;
00069 }
00070
00085 int
00086 Vect_map_add_dblink(struct Map_info *Map, int number, const char *name,
00087 const char *table, const char *key, const char *db,
00088 const char *driver)
00089 {
00090 int ret;
00091
00092 if (number == 0) {
00093 G_warning(_("Layer number must be 1 or greater"));
00094 return -1;
00095 }
00096
00097 if (Map->mode != GV_MODE_WRITE && Map->mode != GV_MODE_RW) {
00098 G_warning(_("Unable to add database link, map is not opened in WRITE mode"));
00099 return -1;
00100 }
00101
00102 ret = Vect_add_dblink(Map->dblnk, number, name, table, key, db, driver);
00103 if (ret == -1) {
00104 G_warning(_("Unable to add database link"));
00105 return -1;
00106 }
00107
00108 ret = Vect_write_dblinks(Map);
00109 if (ret == -1) {
00110 G_warning(_("Unable to write database links"));
00111 return -1;
00112 }
00113 return 0;
00114 }
00115
00125 int Vect_map_del_dblink(struct Map_info *Map, int field)
00126 {
00127 int i, j, ret;
00128 struct dblinks *links;
00129
00130 G_debug(4, "Vect_map_del_dblink() field = %d", field);
00131 links = Map->dblnk;
00132
00133 ret = -1;
00134 for (i = 0; i < links->n_fields; i++) {
00135 if (links->field[i].number == field) {
00136 for (j = i; j < links->n_fields - 1; j++) {
00137 links->field[j].number = links->field[j + 1].number;
00138 links->field[j].name = links->field[j + 1].name;
00139 links->field[j].table = links->field[j + 1].table;
00140 links->field[j].key = links->field[j + 1].key;
00141 links->field[j].database = links->field[j + 1].database;
00142 links->field[j].driver = links->field[j + 1].driver;
00143 }
00144 ret = 0;
00145 links->n_fields--;
00146 }
00147 }
00148
00149 if (ret == -1)
00150 return -1;
00151
00152
00153 ret = Vect_write_dblinks(Map);
00154 if (ret == -1) {
00155 G_warning(_("Unable to write database links"));
00156 return -1;
00157 }
00158
00159 return 0;
00160 }
00161
00171 int Vect_map_check_dblink(struct Map_info *Map, int field)
00172 {
00173 return Vect_check_dblink(Map->dblnk, field);
00174 }
00175
00185 int Vect_check_dblink(struct dblinks *p, int field)
00186 {
00187 int i;
00188
00189 G_debug(3, "Vect_check_dblink: field %d", field);
00190
00191 for (i = 0; i < p->n_fields; i++) {
00192 if (p->field[i].number == field) {
00193 return 1;
00194 }
00195 }
00196 return 0;
00197 }
00198
00199
00213 int
00214 Vect_add_dblink(struct dblinks *p, int number, const char *name,
00215 const char *table, const char *key, const char *db,
00216 const char *driver)
00217 {
00218 int ret;
00219
00220 G_debug(3, "Field number <%d>, name <%s>", number, name);
00221 ret = Vect_check_dblink(p, number);
00222 if (ret == 1) {
00223 G_warning(_("Layer number %d or name <%s> already exists"), number,
00224 name);
00225 return -1;
00226 }
00227
00228 if (p->n_fields == p->alloc_fields) {
00229 p->alloc_fields += 10;
00230 p->field = (struct field_info *)G_realloc((void *)p->field,
00231 p->alloc_fields *
00232 sizeof(struct field_info));
00233 }
00234
00235 p->field[p->n_fields].number = number;
00236
00237 if (name != NULL)
00238 p->field[p->n_fields].name = G_store(name);
00239 else
00240 p->field[p->n_fields].name = NULL;
00241
00242 if (table != NULL)
00243 p->field[p->n_fields].table = G_store(table);
00244 else
00245 p->field[p->n_fields].table = NULL;
00246
00247 if (key != NULL)
00248 p->field[p->n_fields].key = G_store(key);
00249 else
00250 p->field[p->n_fields].key = NULL;
00251
00252 if (db != NULL)
00253 p->field[p->n_fields].database = G_store(db);
00254 else
00255 p->field[p->n_fields].database = NULL;
00256
00257 if (driver != NULL)
00258 p->field[p->n_fields].driver = G_store(driver);
00259 else
00260 p->field[p->n_fields].driver = NULL;
00261
00262 p->n_fields++;
00263
00264 return 0;
00265 }
00266
00277 struct field_info
00278 *Vect_default_field_info(struct Map_info *Map,
00279 int field, const char *field_name, int type)
00280 {
00281 struct field_info *fi;
00282 char buf[1000], buf2[1000];
00283 const char *schema;
00284 const char *drv, *db;
00285 dbConnection connection;
00286
00287 G_debug(1, "Vect_default_field_info(): map = %s field = %d", Map->name,
00288 field);
00289
00290 db_get_connection(&connection);
00291 drv = G__getenv2("DB_DRIVER", G_VAR_MAPSET);
00292 db = G__getenv2("DB_DATABASE", G_VAR_MAPSET);
00293
00294 G_debug(2, "drv = %s db = %s", drv, db);
00295
00296
00297 if (!connection.driverName && !connection.databaseName) {
00298
00299 db_set_default_connection();
00300 db_get_connection(&connection);
00301
00302 G_warning(_("Default driver / database set to:\n"
00303 "driver: %s\ndatabase: %s"), connection.driverName,
00304 connection.databaseName);
00305 }
00306
00307
00308 else if (!connection.driverName) {
00309 G_fatal_error(_("Default driver is not set"));
00310 }
00311 else if (!connection.databaseName) {
00312 G_fatal_error(_("Default database is not set"));
00313 }
00314
00315 drv = connection.driverName;
00316 db = connection.databaseName;
00317
00318 fi = (struct field_info *)G_malloc(sizeof(struct field_info));
00319
00320 fi->number = field;
00321 if (field_name != NULL)
00322 fi->name = G_store(field_name);
00323 else
00324 fi->name = NULL;
00325
00326
00327 if (type == GV_1TABLE) {
00328 sprintf(buf, "%s", Map->name);
00329 }
00330 else {
00331 if (field_name != NULL && strlen(field_name) > 0)
00332 sprintf(buf, "%s_%s", Map->name, field_name);
00333 else
00334 sprintf(buf, "%s_%d", Map->name, field);
00335 }
00336
00337 schema = connection.schemaName;
00338 if (schema && strlen(schema) > 0) {
00339 sprintf(buf2, "%s.%s", schema, buf);
00340 fi->table = G_store(buf2);
00341 }
00342 else {
00343 fi->table = G_store(buf);
00344 }
00345
00346 fi->key = G_store("cat");
00347 fi->database = G_store(db);
00348 fi->driver = G_store(drv);
00349
00350 return (fi);
00351 }
00352
00364 struct field_info *Vect_get_dblink(struct Map_info *Map, int link)
00365 {
00366 struct field_info *fi;
00367
00368 G_debug(1, "Vect_get_dblink(): link = %d", link);
00369
00370 if (link >= Map->dblnk->n_fields) {
00371 G_warning(_("Requested dblink %d, maximum link number %d"), link,
00372 Map->dblnk->n_fields - 1);
00373 return NULL;
00374 }
00375
00376 fi = (struct field_info *)malloc(sizeof(struct field_info));
00377 fi->number = Map->dblnk->field[link].number;
00378
00379 if (Map->dblnk->field[link].name != NULL)
00380 fi->name = G_store(Map->dblnk->field[link].name);
00381 else
00382 fi->name = NULL;
00383
00384 fi->table = G_store(Map->dblnk->field[link].table);
00385 fi->key = G_store(Map->dblnk->field[link].key);
00386 fi->database = Vect_subst_var(Map->dblnk->field[link].database, Map);
00387 fi->driver = G_store(Map->dblnk->field[link].driver);
00388
00389 return fi;
00390 }
00391
00404 struct field_info *Vect_get_field(struct Map_info *Map, int field)
00405 {
00406 int i;
00407 struct field_info *fi = NULL;
00408
00409 G_debug(1, "Vect_get_field(): field = %d", field);
00410
00411 for (i = 0; i < Map->dblnk->n_fields; i++) {
00412 if (Map->dblnk->field[i].number == field) {
00413 fi = Vect_get_dblink(Map, i);
00414 break;
00415 }
00416 }
00417
00418 return fi;
00419 }
00420
00431 int Vect_read_dblinks(struct Map_info *Map)
00432 {
00433 FILE *fd;
00434 char file[1024], buf[2001];
00435 char tab[1024], col[1024], db[1024], drv[1024], fldstr[1024], *fldname;
00436 int fld;
00437 char *c;
00438 int row, rule;
00439 struct dblinks *dbl;
00440 char **tokens;
00441 int ntok, i;
00442
00443 G_debug(1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name,
00444 Map->mapset);
00445
00446 dbl = Map->dblnk;
00447 Vect_reset_dblinks(dbl);
00448
00449 G_debug(3, "Searching for FID column in OGR DB");
00450 if (Map->format == GV_FORMAT_OGR) {
00451
00452 #if GDAL_VERSION_NUM > 1320 && HAVE_OGR
00453 int layer, nLayers;
00454 OGRDataSourceH Ogr_ds;
00455 OGRLayerH Ogr_layer = NULL;
00456 OGRFeatureDefnH Ogr_featuredefn;
00457 char ogr_fid_col[1024];
00458
00459
00460 G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00461
00462
00463 OGRRegisterAll();
00464
00465
00466 Ogr_ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
00467 if (Ogr_ds == NULL)
00468 G_fatal_error("Cannot open OGR data source '%s'",
00469 Map->fInfo.ogr.dsn);
00470 Map->fInfo.ogr.ds = Ogr_ds;
00471
00472
00473 layer = -1;
00474 nLayers = OGR_DS_GetLayerCount(Ogr_ds);
00475
00476 G_debug(3, "%d layers (maps) found in data source", nLayers);
00477
00478 G_debug(3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
00479 Ogr_layer = OGR_DS_GetLayerByName(Ogr_ds, Map->fInfo.ogr.layer_name);
00480 if (Ogr_layer == NULL) {
00481 OGR_DS_Destroy(Ogr_ds);
00482 G_fatal_error("Cannot open layer '%s'",
00483 Map->fInfo.ogr.layer_name);
00484 }
00485 Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
00486 G_debug(3, "layer %s, FID col name: %s",
00487 OGR_FD_GetName(Ogr_featuredefn),
00488 OGR_L_GetFIDColumn(Ogr_layer));
00489 Map->fInfo.ogr.layer = Ogr_layer;
00490 G_debug(3, "OGR Map->fInfo.ogr.layer %p opened",
00491 Map->fInfo.ogr.layer);
00492
00493
00494 sprintf(ogr_fid_col, "%s", OGR_L_GetFIDColumn(Map->fInfo.ogr.layer));
00495 G_debug(3, "Using FID column <%s> in OGR DB", ogr_fid_col);
00496 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, ogr_fid_col,
00497 Map->fInfo.ogr.dsn, "ogr");
00498 #else
00499 dbDriver *driver;
00500 dbCursor cursor;
00501 dbString sql;
00502 int FID = 0, OGC_FID = 0, OGR_FID = 0, GID = 0;
00503
00504 G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00505
00506
00507 db_init_string(&sql);
00508
00509 driver = db_start_driver_open_database("ogr", Map->fInfo.ogr.dsn);
00510
00511 if (driver == NULL) {
00512 G_warning(_("Unable to open OGR DBMI driver"));
00513 return -1;
00514 }
00515
00516
00517 db_auto_print_errors(0);
00518 sprintf(buf, "select FID from %s where FID > 0",
00519 Map->fInfo.ogr.layer_name);
00520 db_set_string(&sql, buf);
00521
00522 if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00523 DB_OK) {
00524
00525 G_debug(3, "Failed. Now searching for ogc_fid column in OGR DB");
00526 sprintf(buf, "select ogc_fid from %s where ogc_fid > 0",
00527 Map->fInfo.ogr.layer_name);
00528 db_set_string(&sql, buf);
00529
00530 if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00531 DB_OK) {
00532
00533 G_debug(3,
00534 "Failed. Now searching for ogr_fid column in OGR DB");
00535 sprintf(buf, "select ogr_fid from %s where ogr_fid > 0",
00536 Map->fInfo.ogr.layer_name);
00537 db_set_string(&sql, buf);
00538
00539 if (db_open_select_cursor
00540 (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00541
00542 G_debug(3,
00543 "Failed. Now searching for gid column in OGR DB");
00544 sprintf(buf, "select gid from %s where gid > 0",
00545 Map->fInfo.ogr.layer_name);
00546 db_set_string(&sql, buf);
00547
00548 if (db_open_select_cursor
00549 (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00550
00551 G_warning(_("All FID tests failed. Neither 'FID' nor 'ogc_fid' "
00552 "nor 'ogr_fid' nor 'gid' available in OGR DB table"));
00553 db_close_database_shutdown_driver(driver);
00554 return 0;
00555 }
00556 else
00557 GID = 1;
00558 }
00559 else
00560 OGR_FID = 1;
00561 }
00562 else
00563 OGC_FID = 1;
00564 }
00565 else
00566 FID = 1;
00567
00568 G_debug(3, "FID: %d, OGC_FID: %d, OGR_FID: %d, GID: %d", FID, OGC_FID,
00569 OGR_FID, GID);
00570
00571 db_close_cursor(&cursor);
00572 db_close_database_shutdown_driver(driver);
00573 db_auto_print_errors(1);
00574
00575 if (FID) {
00576 G_debug(3, "Using FID column in OGR DB");
00577 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, "FID",
00578 Map->fInfo.ogr.dsn, "ogr");
00579 }
00580 else {
00581 if (OGC_FID) {
00582 G_debug(3, "Using ogc_fid column in OGR DB");
00583 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00584 "ogc_fid", Map->fInfo.ogr.dsn, "ogr");
00585 }
00586 else {
00587 if (OGR_FID) {
00588 G_debug(3, "Using ogr_fid column in OGR DB");
00589 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00590 "ogr_fid", Map->fInfo.ogr.dsn, "ogr");
00591 }
00592 else {
00593 if (GID) {
00594 G_debug(3, "Using gid column in OGR DB");
00595 Vect_add_dblink(dbl, 1, NULL,
00596 Map->fInfo.ogr.layer_name, "gid",
00597 Map->fInfo.ogr.dsn, "ogr");
00598 }
00599 }
00600 }
00601 }
00602 #endif
00603 return (1);
00604 }
00605 else if (Map->format != GV_FORMAT_NATIVE) {
00606 G_fatal_error(_("Don't know how to read links for format %d"),
00607 Map->format);
00608 }
00609
00610 sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00611 Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00612 GRASS_VECT_DBLN_ELEMENT);
00613 G_debug(1, "dbln file: %s", file);
00614
00615 fd = fopen(file, "r");
00616 if (fd == NULL) {
00617 G_debug(1, "Cannot open vector database definition file");
00618 return (-1);
00619 }
00620
00621 row = 0;
00622 rule = 0;
00623 while (G_getl2(buf, 2000, fd)) {
00624 row++;
00625 G_chop(buf);
00626 G_debug(1, "dbln: %s", buf);
00627
00628 c = (char *)strchr(buf, '#');
00629 if (c != NULL)
00630 *c = '\0';
00631
00632 if (strlen(buf) == 0)
00633 continue;
00634
00635 tokens = G_tokenize(buf, " |");
00636 ntok = G_number_of_tokens(tokens);
00637
00638 if (ntok < 2 || (ntok < 5 && rule < 1)) {
00639 G_warning(_("Error in rule on row %d in %s"), row, file);
00640 continue;
00641 }
00642
00643 strcpy(fldstr, tokens[0]);
00644 strcpy(tab, tokens[1]);
00645 if (ntok > 2) {
00646 strcpy(col, tokens[2]);
00647 if (ntok > 3) {
00648 strcpy(db, tokens[3]);
00649
00650 for (i=4; i < ntok-1; i++) {
00651 strcat(db, " ");
00652 strcat(db, tokens[i]);
00653 }
00654
00655 strcpy(drv, tokens[ntok-1]);
00656 }
00657 }
00658 G_free_tokens(tokens);
00659
00660
00661 fldname = strchr(fldstr, '/');
00662 if (fldname != NULL) {
00663 fldname[0] = 0;
00664 fldname++;
00665 }
00666 fld = atoi(fldstr);
00667
00668 Vect_add_dblink(dbl, fld, fldname, tab, col, db, drv);
00669
00670 G_debug(1,
00671 "field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
00672 fld, fldname, tab, col, db, drv);
00673
00674 rule++;
00675 }
00676 fclose(fd);
00677
00678 G_debug(1, "Dblinks read");
00679 return (rule);
00680 }
00681
00690 int Vect_write_dblinks(struct Map_info *Map)
00691 {
00692 int i;
00693 FILE *fd;
00694 char file[GPATH_MAX], buf[GPATH_MAX];
00695 struct dblinks *dbl;
00696
00697 G_debug(1, "Vect_write_dblinks(): map = %s, mapset = %s", Map->name,
00698 Map->mapset);
00699
00700 dbl = Map->dblnk;
00701
00702 sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00703 Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00704 GRASS_VECT_DBLN_ELEMENT);
00705 G_debug(1, "dbln file: %s", file);
00706
00707 fd = fopen(file, "w");
00708 if (fd == NULL) {
00709 G_warning(_("Unable to open vector database definition file '%s'"),
00710 file);
00711 return (-1);
00712 }
00713
00714 for (i = 0; i < dbl->n_fields; i++) {
00715 if (dbl->field[i].name != NULL)
00716 sprintf(buf, "%d/%s", dbl->field[i].number, dbl->field[i].name);
00717 else
00718 sprintf(buf, "%d", dbl->field[i].number);
00719
00720 fprintf(fd, "%s %s %s %s %s\n", buf, dbl->field[i].table,
00721 dbl->field[i].key, dbl->field[i].database,
00722 dbl->field[i].driver);
00723 G_debug(1, "%s %s %s %s %s", buf, dbl->field[i].table,
00724 dbl->field[i].key, dbl->field[i].database,
00725 dbl->field[i].driver);
00726 }
00727 fclose(fd);
00728
00729 G_debug(1, "Dblinks written");
00730 return 0;
00731 }
00732
00741 char *Vect_subst_var(const char *in, struct Map_info *Map)
00742 {
00743 char *c;
00744 char buf[1000], str[1000];
00745
00746 G_debug(3, "Vect_subst_var(): in = %s, map = %s, mapset = %s", in,
00747 Map->name, Map->mapset);
00748
00749 strcpy(str, in);
00750
00751 strcpy(buf, str);
00752 c = (char *)strstr(buf, "$GISDBASE");
00753 if (c != NULL) {
00754 *c = '\0';
00755 sprintf(str, "%s%s%s", buf, Map->gisdbase, c + 9);
00756 }
00757
00758 strcpy(buf, str);
00759 c = (char *)strstr(buf, "$LOCATION_NAME");
00760 if (c != NULL) {
00761 *c = '\0';
00762 sprintf(str, "%s%s%s", buf, Map->location, c + 14);
00763 }
00764
00765 strcpy(buf, str);
00766 c = (char *)strstr(buf, "$MAPSET");
00767 if (c != NULL) {
00768 *c = '\0';
00769 sprintf(str, "%s%s%s", buf, Map->mapset, c + 7);
00770 }
00771
00772 strcpy(buf, str);
00773 c = (char *)strstr(buf, "$MAP");
00774 if (c != NULL) {
00775 *c = '\0';
00776 sprintf(str, "%s%s%s", buf, Map->name, c + 4);
00777 }
00778
00779 G_debug(3, " -> %s", str);
00780 return (G_store(str));
00781 }
00782
00794 void Vect_set_db_updated(struct Map_info *Map)
00795 {
00796 if (strcmp(Map->mapset, G_mapset()) != 0) {
00797 G_fatal_error(_("Bug: attempt to update map which is not in current mapset"));
00798 }
00799
00800 Vect_write_dblinks(Map);
00801 }