GRASS Programmer's Manual
6.4.1(2011)
|
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> /* needed for FID detection */ 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 /* write it immediately otherwise it is lost if module crashes */ 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) { /* field found */ 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 /* write it immediately otherwise it is lost if module crashes */ 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 /* Set default values and create dbf db dir */ 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 /* they must be a matched pair, so if one is set but not the other 00307 then give up and let the user figure it out */ 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 /* Table name */ 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"); /* Should be: id/fid/gfid/... ? */ 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 /* seems to be fixed after 1320 release */ 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 /* we open the connection to fetch the FID column name */ 00463 OGRRegisterAll(); 00464 00465 /*Data source handle */ 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 /* Layer number */ 00473 layer = -1; 00474 nLayers = OGR_DS_GetLayerCount(Ogr_ds); /* Layers = Maps in OGR DB */ 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 /* TODO what to do if OGR_L_GetFIDColumn() doesn't return FID name */ 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 /* FID is not available for all OGR drivers */ 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 /* this is a bit stupid, but above FID auto-detection doesn't work yet...: */ 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 /* FID not available, so we try ogc_fid */ 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 /* Neither FID nor ogc_fid available, so we try ogr_fid */ 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 /* Neither FID nor ogc_fid available, so we try gid */ 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 /* neither FID nor ogc_fid nor ogr_fid nor gid available */ 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 /* GDAL_VERSION_NUM > 1320 && HAVE_OGR */ 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) { /* This may be correct, no tables defined */ 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 /* allow for spaces in path names */ 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 /* get field and field name */ 00661 fldname = strchr(fldstr, '/'); 00662 if (fldname != NULL) { /* field has name */ 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) { /* This may be correct, no tables defined */ 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 #ifdef __MINGW32__ 00750 char *cin; 00751 cin = G_str_replace((char *)in, "/", "\\"); 00752 strcpy(str, cin); 00753 G_free(cin); 00754 #else 00755 strcpy(str, in); 00756 #endif 00757 00758 strcpy(buf, str); 00759 c = (char *)strstr(buf, "$GISDBASE"); 00760 if (c != NULL) { 00761 *c = '\0'; 00762 sprintf(str, "%s%s%s", buf, Map->gisdbase, c + 9); 00763 } 00764 00765 strcpy(buf, str); 00766 c = (char *)strstr(buf, "$LOCATION_NAME"); 00767 if (c != NULL) { 00768 *c = '\0'; 00769 sprintf(str, "%s%s%s", buf, Map->location, c + 14); 00770 } 00771 00772 strcpy(buf, str); 00773 c = (char *)strstr(buf, "$MAPSET"); 00774 if (c != NULL) { 00775 *c = '\0'; 00776 sprintf(str, "%s%s%s", buf, Map->mapset, c + 7); 00777 } 00778 00779 strcpy(buf, str); 00780 c = (char *)strstr(buf, "$MAP"); 00781 if (c != NULL) { 00782 *c = '\0'; 00783 sprintf(str, "%s%s%s", buf, Map->name, c + 4); 00784 } 00785 00786 G_debug(3, " -> %s", str); 00787 return (G_store(str)); 00788 } 00789 00801 void Vect_set_db_updated(struct Map_info *Map) 00802 { 00803 if (strcmp(Map->mapset, G_mapset()) != 0) { 00804 G_fatal_error(_("Bug: attempt to update map which is not in current mapset")); 00805 } 00806 00807 Vect_write_dblinks(Map); 00808 }