field.c

Go to the documentation of this file.
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     int ndef;
00434     FILE *fd;
00435     char file[1024], buf[2001];
00436     char tab[1024], col[1024], db[1024], drv[1024], fldstr[1024], *fldname;
00437     int fld;
00438     char *c;
00439     int row, rule;
00440     struct dblinks *dbl;
00441 
00442     G_debug(1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name,
00443             Map->mapset);
00444 
00445     dbl = Map->dblnk;
00446     Vect_reset_dblinks(dbl);
00447 
00448     G_debug(3, "Searching for FID column in OGR DB");
00449     if (Map->format == GV_FORMAT_OGR) {
00450 
00451 #if GDAL_VERSION_NUM > 1320 && HAVE_OGR /* seems to be fixed after 1320 release */
00452         int layer, nLayers;
00453         OGRDataSourceH Ogr_ds;
00454         OGRLayerH Ogr_layer = NULL;
00455         OGRFeatureDefnH Ogr_featuredefn;
00456         char ogr_fid_col[1024];
00457 
00458 
00459         G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00460 
00461         /* we open the connection to fetch the FID column name */
00462         OGRRegisterAll();
00463 
00464         /*Data source handle */
00465         Ogr_ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
00466         if (Ogr_ds == NULL)
00467             G_fatal_error("Cannot open OGR data source '%s'",
00468                           Map->fInfo.ogr.dsn);
00469         Map->fInfo.ogr.ds = Ogr_ds;
00470 
00471         /* Layer number */
00472         layer = -1;
00473         nLayers = OGR_DS_GetLayerCount(Ogr_ds); /* Layers = Maps in OGR DB */
00474 
00475         G_debug(3, "%d layers (maps) found in data source", nLayers);
00476 
00477         G_debug(3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
00478         Ogr_layer = OGR_DS_GetLayerByName(Ogr_ds, Map->fInfo.ogr.layer_name);
00479         if (Ogr_layer == NULL) {
00480             OGR_DS_Destroy(Ogr_ds);
00481             G_fatal_error("Cannot open layer '%s'",
00482                           Map->fInfo.ogr.layer_name);
00483         }
00484         Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
00485         G_debug(3, "layer %s, FID col name: %s",
00486                 OGR_FD_GetName(Ogr_featuredefn),
00487                 OGR_L_GetFIDColumn(Ogr_layer));
00488         Map->fInfo.ogr.layer = Ogr_layer;
00489         G_debug(3, "OGR Map->fInfo.ogr.layer %p opened",
00490                 Map->fInfo.ogr.layer);
00491 
00492         /* TODO what to do if OGR_L_GetFIDColumn() doesn't return FID name */
00493         sprintf(ogr_fid_col, "%s", OGR_L_GetFIDColumn(Map->fInfo.ogr.layer));
00494         G_debug(3, "Using FID column <%s> in OGR DB", ogr_fid_col);
00495         Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, ogr_fid_col,
00496                         Map->fInfo.ogr.dsn, "ogr");
00497 #else
00498         dbDriver *driver;
00499         dbCursor cursor;
00500         dbString sql;
00501         int FID = 0, OGC_FID = 0, OGR_FID = 0, GID = 0;
00502 
00503         G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00504 
00505         /* FID is not available for all OGR drivers */
00506         db_init_string(&sql);
00507 
00508         driver = db_start_driver_open_database("ogr", Map->fInfo.ogr.dsn);
00509 
00510         if (driver == NULL) {
00511             G_warning(_("Unable to open OGR DBMI driver"));
00512             return -1;
00513         }
00514 
00515         /* this is a bit stupid, but above FID auto-detection doesn't work yet...: */
00516         db_auto_print_errors(0);
00517         sprintf(buf, "select FID from %s where FID > 0",
00518                 Map->fInfo.ogr.layer_name);
00519         db_set_string(&sql, buf);
00520 
00521         if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00522             DB_OK) {
00523             /* FID not available, so we try ogc_fid */
00524             G_debug(3, "Failed. Now searching for ogc_fid column in OGR DB");
00525             sprintf(buf, "select ogc_fid from %s where ogc_fid > 0",
00526                     Map->fInfo.ogr.layer_name);
00527             db_set_string(&sql, buf);
00528 
00529             if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00530                 DB_OK) {
00531                 /* Neither FID nor ogc_fid available, so we try ogr_fid */
00532                 G_debug(3,
00533                         "Failed. Now searching for ogr_fid column in OGR DB");
00534                 sprintf(buf, "select ogr_fid from %s where ogr_fid > 0",
00535                         Map->fInfo.ogr.layer_name);
00536                 db_set_string(&sql, buf);
00537 
00538                 if (db_open_select_cursor
00539                     (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00540                     /* Neither FID nor ogc_fid available, so we try gid */
00541                     G_debug(3,
00542                             "Failed. Now searching for gid column in OGR DB");
00543                     sprintf(buf, "select gid from %s where gid > 0",
00544                             Map->fInfo.ogr.layer_name);
00545                     db_set_string(&sql, buf);
00546 
00547                     if (db_open_select_cursor
00548                         (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00549                         /* neither FID nor ogc_fid nor ogr_fid nor gid available */
00550                         G_warning(_("All FID tests failed. Neither 'FID' nor 'ogc_fid' "
00551                                    "nor 'ogr_fid' nor 'gid' available in OGR DB table"));
00552                         db_close_database_shutdown_driver(driver);
00553                         return 0;
00554                     }
00555                     else
00556                         GID = 1;
00557                 }
00558                 else
00559                     OGR_FID = 1;
00560             }
00561             else
00562                 OGC_FID = 1;
00563         }
00564         else
00565             FID = 1;
00566 
00567         G_debug(3, "FID: %d, OGC_FID: %d, OGR_FID: %d, GID: %d", FID, OGC_FID,
00568                 OGR_FID, GID);
00569 
00570         db_close_cursor(&cursor);
00571         db_close_database_shutdown_driver(driver);
00572         db_auto_print_errors(1);
00573 
00574         if (FID) {
00575             G_debug(3, "Using FID column in OGR DB");
00576             Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, "FID",
00577                             Map->fInfo.ogr.dsn, "ogr");
00578         }
00579         else {
00580             if (OGC_FID) {
00581                 G_debug(3, "Using ogc_fid column in OGR DB");
00582                 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00583                                 "ogc_fid", Map->fInfo.ogr.dsn, "ogr");
00584             }
00585             else {
00586                 if (OGR_FID) {
00587                     G_debug(3, "Using ogr_fid column in OGR DB");
00588                     Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00589                                     "ogr_fid", Map->fInfo.ogr.dsn, "ogr");
00590                 }
00591                 else {
00592                     if (GID) {
00593                         G_debug(3, "Using gid column in OGR DB");
00594                         Vect_add_dblink(dbl, 1, NULL,
00595                                         Map->fInfo.ogr.layer_name, "gid",
00596                                         Map->fInfo.ogr.dsn, "ogr");
00597                     }
00598                 }
00599             }
00600         }
00601 #endif /* GDAL_VERSION_NUM > 1320 && HAVE_OGR */
00602         return (1);
00603     }
00604     else if (Map->format != GV_FORMAT_NATIVE) {
00605         G_fatal_error(_("Don't know how to read links for format %d"),
00606                       Map->format);
00607     }
00608 
00609     sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00610             Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00611             GRASS_VECT_DBLN_ELEMENT);
00612     G_debug(1, "dbln file: %s", file);
00613 
00614     fd = fopen(file, "r");
00615     if (fd == NULL) {           /* This may be correct, no tables defined */
00616         G_debug(1, "Cannot open vector database definition file");
00617         return (-1);
00618     }
00619 
00620     row = 0;
00621     rule = 0;
00622     while (G_getl2(buf, 2000, fd)) {
00623         row++;
00624         G_chop(buf);
00625         G_debug(1, "dbln: %s", buf);
00626 
00627         c = (char *)strchr(buf, '#');
00628         if (c != NULL)
00629             *c = '\0';
00630 
00631         if (strlen(buf) == 0)
00632             continue;
00633 
00634         ndef = sscanf(buf, "%s %s %s %s %s", fldstr, tab, col, db, drv);
00635 
00636         if (ndef < 2 || (ndef < 5 && rule < 1)) {
00637             G_warning(_("Error in rule on row %d in %s"), row, file);
00638             continue;
00639         }
00640 
00641         /* get field and field name */
00642         fldname = strchr(fldstr, '/');
00643         if (fldname != NULL) {  /* field has name */
00644             fldname[0] = 0;
00645             fldname++;
00646         }
00647         fld = atoi(fldstr);
00648 
00649         Vect_add_dblink(dbl, fld, fldname, tab, col, db, drv);
00650 
00651         G_debug(1,
00652                 "field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
00653                 fld, fldname, tab, col, db, drv);
00654 
00655         rule++;
00656     }
00657     fclose(fd);
00658 
00659     G_debug(1, "Dblinks read");
00660     return (rule);
00661 }
00662 
00671 int Vect_write_dblinks(struct Map_info *Map)
00672 {
00673     int i;
00674     FILE *fd;
00675     char file[GPATH_MAX], buf[GPATH_MAX];
00676     struct dblinks *dbl;
00677 
00678     G_debug(1, "Vect_write_dblinks(): map = %s, mapset = %s", Map->name,
00679             Map->mapset);
00680 
00681     dbl = Map->dblnk;
00682 
00683     sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00684             Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00685             GRASS_VECT_DBLN_ELEMENT);
00686     G_debug(1, "dbln file: %s", file);
00687 
00688     fd = fopen(file, "w");
00689     if (fd == NULL) {           /* This may be correct, no tables defined */
00690         G_warning(_("Unable to open vector database definition file '%s'"),
00691                   file);
00692         return (-1);
00693     }
00694 
00695     for (i = 0; i < dbl->n_fields; i++) {
00696         if (dbl->field[i].name != NULL)
00697             sprintf(buf, "%d/%s", dbl->field[i].number, dbl->field[i].name);
00698         else
00699             sprintf(buf, "%d", dbl->field[i].number);
00700 
00701         fprintf(fd, "%s %s %s %s %s\n", buf, dbl->field[i].table,
00702                 dbl->field[i].key, dbl->field[i].database,
00703                 dbl->field[i].driver);
00704         G_debug(1, "%s %s %s %s %s", buf, dbl->field[i].table,
00705                 dbl->field[i].key, dbl->field[i].database,
00706                 dbl->field[i].driver);
00707     }
00708     fclose(fd);
00709 
00710     G_debug(1, "Dblinks written");
00711     return 0;
00712 }
00713 
00722 char *Vect_subst_var(const char *in, struct Map_info *Map)
00723 {
00724     char *c;
00725     char buf[1000], str[1000];
00726 
00727     G_debug(3, "Vect_subst_var(): in = %s, map = %s, mapset = %s", in,
00728             Map->name, Map->mapset);
00729 
00730     strcpy(str, in);
00731 
00732     strcpy(buf, str);
00733     c = (char *)strstr(buf, "$GISDBASE");
00734     if (c != NULL) {
00735         *c = '\0';
00736         sprintf(str, "%s%s%s", buf, Map->gisdbase, c + 9);
00737     }
00738 
00739     strcpy(buf, str);
00740     c = (char *)strstr(buf, "$LOCATION_NAME");
00741     if (c != NULL) {
00742         *c = '\0';
00743         sprintf(str, "%s%s%s", buf, Map->location, c + 14);
00744     }
00745 
00746     strcpy(buf, str);
00747     c = (char *)strstr(buf, "$MAPSET");
00748     if (c != NULL) {
00749         *c = '\0';
00750         sprintf(str, "%s%s%s", buf, Map->mapset, c + 7);
00751     }
00752 
00753     strcpy(buf, str);
00754     c = (char *)strstr(buf, "$MAP");
00755     if (c != NULL) {
00756         *c = '\0';
00757         sprintf(str, "%s%s%s", buf, Map->name, c + 4);
00758     }
00759 
00760     G_debug(3, "  -> %s", str);
00761     return (G_store(str));
00762 }
00763 
00775 void Vect_set_db_updated(struct Map_info *Map)
00776 {
00777     if (strcmp(Map->mapset, G_mapset()) != 0) {
00778         G_fatal_error(_("Bug: attempt to update map which is not in current mapset"));
00779     }
00780 
00781     Vect_write_dblinks(Map);
00782 }
Generated on Tue Apr 6 13:28:10 2010 for GRASS Programmer's Manual by  doxygen 1.6.3