GRASS Programmer's Manual  6.4.1(2011)
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     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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines