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 
00041 struct dblinks *Vect_new_dblinks_struct(void)
00042 {
00043     struct dblinks *p;
00044 
00045     p = (struct dblinks *)G_malloc(sizeof(struct dblinks));
00046 
00047     if (p) {
00048         p->alloc_fields = p->n_fields = 0;
00049         p->field = NULL;
00050     }
00051 
00052     return p;
00053 }
00054 
00062 void Vect_reset_dblinks(struct dblinks *p)
00063 {
00064     p->n_fields = 0;
00065 }
00066 
00081 int
00082 Vect_map_add_dblink(struct Map_info *Map, int number, const char *name,
00083                     const char *table, const char *key, const char *db,
00084                     const char *driver)
00085 {
00086     int ret;
00087 
00088     if (number == 0) {
00089         G_warning(_("Layer number must be 1 or greater"));
00090         return -1;
00091     }
00092 
00093     if (Map->mode != GV_MODE_WRITE && Map->mode != GV_MODE_RW) {
00094         G_warning(_("Unable to add database link, map is not opened in WRITE mode"));
00095         return -1;
00096     }
00097 
00098     ret = Vect_add_dblink(Map->dblnk, number, name, table, key, db, driver);
00099     if (ret == -1) {
00100         G_warning(_("Unable to add database link"));
00101         return -1;
00102     }
00103     /* write it immediately otherwise it is lost if module crashes */
00104     ret = Vect_write_dblinks(Map);
00105     if (ret == -1) {
00106         G_warning(_("Unable to write database links"));
00107         return -1;
00108     }
00109     return 0;
00110 }
00111 
00121 int Vect_map_del_dblink(struct Map_info *Map, int field)
00122 {
00123     int i, j, ret;
00124     struct dblinks *links;
00125 
00126     G_debug(4, "Vect_map_del_dblink() field = %d", field);
00127     links = Map->dblnk;
00128 
00129     ret = -1;
00130     for (i = 0; i < links->n_fields; i++) {
00131         if (links->field[i].number == field) {  /* field found */
00132             for (j = i; j < links->n_fields - 1; j++) {
00133                 links->field[j].number = links->field[j + 1].number;
00134                 links->field[j].name = links->field[j + 1].name;
00135                 links->field[j].table = links->field[j + 1].table;
00136                 links->field[j].key = links->field[j + 1].key;
00137                 links->field[j].database = links->field[j + 1].database;
00138                 links->field[j].driver = links->field[j + 1].driver;
00139             }
00140             ret = 0;
00141             links->n_fields--;
00142         }
00143     }
00144 
00145     if (ret == -1)
00146         return -1;
00147 
00148     /* write it immediately otherwise it is lost if module crashes */
00149     ret = Vect_write_dblinks(Map);
00150     if (ret == -1) {
00151         G_warning(_("Unable to write database links"));
00152         return -1;
00153     }
00154 
00155     return 0;
00156 }
00157 
00167 int Vect_map_check_dblink(struct Map_info *Map, int field)
00168 {
00169     return Vect_check_dblink(Map->dblnk, field);
00170 }
00171 
00181 int Vect_check_dblink(struct dblinks *p, int field)
00182 {
00183     int i;
00184 
00185     G_debug(3, "Vect_check_dblink: field %d", field);
00186 
00187     for (i = 0; i < p->n_fields; i++) {
00188         if (p->field[i].number == field) {
00189             return 1;
00190         }
00191     }
00192     return 0;
00193 }
00194 
00195 
00209 int
00210 Vect_add_dblink(struct dblinks *p, int number, const char *name,
00211                 const char *table, const char *key, const char *db,
00212                 const char *driver)
00213 {
00214     int ret;
00215 
00216     G_debug(3, "Field number <%d>, name <%s>", number, name);
00217     ret = Vect_check_dblink(p, number);
00218     if (ret == 1) {
00219         G_warning(_("Layer number %d or name <%s> already exists"), number,
00220                   name);
00221         return -1;
00222     }
00223 
00224     if (p->n_fields == p->alloc_fields) {
00225         p->alloc_fields += 10;
00226         p->field = (struct field_info *)G_realloc((void *)p->field,
00227                                                   p->alloc_fields *
00228                                                   sizeof(struct field_info));
00229     }
00230 
00231     p->field[p->n_fields].number = number;
00232 
00233     if (name != NULL)
00234         p->field[p->n_fields].name = G_store(name);
00235     else
00236         p->field[p->n_fields].name = NULL;
00237 
00238     if (table != NULL)
00239         p->field[p->n_fields].table = G_store(table);
00240     else
00241         p->field[p->n_fields].table = NULL;
00242 
00243     if (key != NULL)
00244         p->field[p->n_fields].key = G_store(key);
00245     else
00246         p->field[p->n_fields].key = NULL;
00247 
00248     if (db != NULL)
00249         p->field[p->n_fields].database = G_store(db);
00250     else
00251         p->field[p->n_fields].database = NULL;
00252 
00253     if (driver != NULL)
00254         p->field[p->n_fields].driver = G_store(driver);
00255     else
00256         p->field[p->n_fields].driver = NULL;
00257 
00258     p->n_fields++;
00259 
00260     return 0;
00261 }
00262 
00273 struct field_info
00274     *Vect_default_field_info(struct Map_info *Map,
00275                              int field, const char *field_name, int type)
00276 {
00277     struct field_info *fi;
00278     char buf[1000], buf2[1000];
00279     const char *schema;
00280     const char *drv, *db;
00281     dbConnection connection;
00282 
00283     G_debug(1, "Vect_default_field_info(): map = %s field = %d", Map->name,
00284             field);
00285 
00286     db_get_connection(&connection);
00287     drv = G__getenv2("DB_DRIVER", G_VAR_MAPSET);
00288     db = G__getenv2("DB_DATABASE", G_VAR_MAPSET);
00289 
00290     G_debug(2, "drv = %s db = %s", drv, db);
00291 
00292 
00293     if (!connection.driverName && !connection.databaseName) {
00294         /* Set default values and create dbf db dir */
00295         db_set_default_connection();
00296         db_get_connection(&connection);
00297 
00298         G_warning(_("Default driver / database set to:\n"
00299                     "driver: %s\ndatabase: %s"), connection.driverName,
00300                   connection.databaseName);
00301     }
00302     /* they must be a matched pair, so if one is set but not the other
00303        then give up and let the user figure it out */
00304     else if (!connection.driverName) {
00305         G_fatal_error(_("Default driver is not set"));
00306     }
00307     else if (!connection.databaseName) {
00308         G_fatal_error(_("Default database is not set"));
00309     }
00310 
00311     drv = connection.driverName;
00312     db = connection.databaseName;
00313 
00314     fi = (struct field_info *)G_malloc(sizeof(struct field_info));
00315 
00316     fi->number = field;
00317     if (field_name != NULL)
00318         fi->name = G_store(field_name);
00319     else
00320         fi->name = NULL;
00321 
00322     /* Table name */
00323     if (type == GV_1TABLE) {
00324         sprintf(buf, "%s", Map->name);
00325     }
00326     else {
00327         if (field_name != NULL && strlen(field_name) > 0)
00328             sprintf(buf, "%s_%s", Map->name, field_name);
00329         else
00330             sprintf(buf, "%s_%d", Map->name, field);
00331     }
00332 
00333     schema = connection.schemaName;
00334     if (schema && strlen(schema) > 0) {
00335         sprintf(buf2, "%s.%s", schema, buf);
00336         fi->table = G_store(buf2);
00337     }
00338     else {
00339         fi->table = G_store(buf);
00340     }
00341 
00342     fi->key = G_store("cat");   /* Should be: id/fid/gfid/... ? */
00343     fi->database = G_store(db);
00344     fi->driver = G_store(drv);
00345 
00346     return (fi);
00347 }
00348 
00360 struct field_info *Vect_get_dblink(struct Map_info *Map, int link)
00361 {
00362     struct field_info *fi;
00363 
00364     G_debug(1, "Vect_get_dblink(): link = %d", link);
00365 
00366     if (link >= Map->dblnk->n_fields) {
00367         G_warning(_("Requested dblink %d, maximum link number %d"), link,
00368                   Map->dblnk->n_fields - 1);
00369         return NULL;
00370     }
00371 
00372     fi = (struct field_info *)malloc(sizeof(struct field_info));
00373     fi->number = Map->dblnk->field[link].number;
00374 
00375     if (Map->dblnk->field[link].name != NULL)
00376         fi->name = G_store(Map->dblnk->field[link].name);
00377     else
00378         fi->name = NULL;
00379 
00380     fi->table = G_store(Map->dblnk->field[link].table);
00381     fi->key = G_store(Map->dblnk->field[link].key);
00382     fi->database = Vect_subst_var(Map->dblnk->field[link].database, Map);
00383     fi->driver = G_store(Map->dblnk->field[link].driver);
00384 
00385     return fi;
00386 }
00387 
00400 struct field_info *Vect_get_field(struct Map_info *Map, int field)
00401 {
00402     int i;
00403     struct field_info *fi = NULL;
00404 
00405     G_debug(1, "Vect_get_field(): field = %d", field);
00406 
00407     for (i = 0; i < Map->dblnk->n_fields; i++) {
00408         if (Map->dblnk->field[i].number == field) {
00409             fi = Vect_get_dblink(Map, i);
00410             break;
00411         }
00412     }
00413 
00414     return fi;
00415 }
00416 
00427 int Vect_read_dblinks(struct Map_info *Map)
00428 {
00429     int ndef;
00430     FILE *fd;
00431     char file[1024], buf[2001];
00432     char tab[1024], col[1024], db[1024], drv[1024], fldstr[1024], *fldname;
00433     int fld;
00434     char *c;
00435     int row, rule;
00436     struct dblinks *dbl;
00437 
00438     G_debug(1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name,
00439             Map->mapset);
00440 
00441     dbl = Map->dblnk;
00442     Vect_reset_dblinks(dbl);
00443 
00444     G_debug(3, "Searching for FID column in OGR DB");
00445     if (Map->format == GV_FORMAT_OGR) {
00446 
00447 #if GDAL_VERSION_NUM > 1320     /* seems to be fixed after 1320 release */
00448         int layer, nLayers;
00449         OGRDataSourceH Ogr_ds;
00450         OGRLayerH Ogr_layer = NULL;
00451         OGRFeatureDefnH Ogr_featuredefn;
00452         char ogr_fid_col[1024];
00453 
00454 
00455         G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00456 
00457         /* we open the connection to fetch the FID column name */
00458         OGRRegisterAll();
00459 
00460         /*Data source handle */
00461         Ogr_ds = OGROpen(Map->fInfo.ogr.dsn, FALSE, NULL);
00462         if (Ogr_ds == NULL)
00463             G_fatal_error("Cannot open OGR data source '%s'",
00464                           Map->fInfo.ogr.dsn);
00465         Map->fInfo.ogr.ds = Ogr_ds;
00466 
00467         /* Layer number */
00468         layer = -1;
00469         nLayers = OGR_DS_GetLayerCount(Ogr_ds); /* Layers = Maps in OGR DB */
00470 
00471         G_debug(3, "%d layers (maps) found in data source", nLayers);
00472 
00473         G_debug(3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
00474         Ogr_layer = OGR_DS_GetLayerByName(Ogr_ds, Map->fInfo.ogr.layer_name);
00475         if (Ogr_layer == NULL) {
00476             OGR_DS_Destroy(Ogr_ds);
00477             G_fatal_error("Cannot open layer '%s'",
00478                           Map->fInfo.ogr.layer_name);
00479         }
00480         Ogr_featuredefn = OGR_L_GetLayerDefn(Ogr_layer);
00481         G_debug(3, "layer %s, FID col name: %s",
00482                 OGR_FD_GetName(Ogr_featuredefn),
00483                 OGR_L_GetFIDColumn(Ogr_layer));
00484         Map->fInfo.ogr.layer = Ogr_layer;
00485         G_debug(3, "OGR Map->fInfo.ogr.layer %p opened",
00486                 Map->fInfo.ogr.layer);
00487 
00488         /* TODO what to do if OGR_L_GetFIDColumn() doesn't return FID name */
00489         sprintf(ogr_fid_col, "%s", OGR_L_GetFIDColumn(Map->fInfo.ogr.layer));
00490         G_debug(3, "Using FID column <%s> in OGR DB", ogr_fid_col);
00491         Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, ogr_fid_col,
00492                         Map->fInfo.ogr.dsn, "ogr");
00493 #else
00494         dbDriver *driver;
00495         dbCursor cursor;
00496         dbString sql;
00497         int FID = 0, OGC_FID = 0, OGR_FID = 0, GID = 0;
00498 
00499         G_debug(3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00500 
00501         /* FID is not available for all OGR drivers */
00502         db_init_string(&sql);
00503 
00504         driver = db_start_driver_open_database("ogr", Map->fInfo.ogr.dsn);
00505 
00506         if (driver == NULL) {
00507             G_warning(_("Unable to open OGR DBMI driver"));
00508             return -1;
00509         }
00510 
00511         /* this is a bit stupid, but above FID auto-detection doesn't work yet...: */
00512         db_auto_print_errors(0);
00513         sprintf(buf, "select FID from %s where FID > 0",
00514                 Map->fInfo.ogr.layer_name);
00515         db_set_string(&sql, buf);
00516 
00517         if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00518             DB_OK) {
00519             /* FID not available, so we try ogc_fid */
00520             G_debug(3, "Failed. Now searching for ogc_fid column in OGR DB");
00521             sprintf(buf, "select ogc_fid from %s where ogc_fid > 0",
00522                     Map->fInfo.ogr.layer_name);
00523             db_set_string(&sql, buf);
00524 
00525             if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) !=
00526                 DB_OK) {
00527                 /* Neither FID nor ogc_fid available, so we try ogr_fid */
00528                 G_debug(3,
00529                         "Failed. Now searching for ogr_fid column in OGR DB");
00530                 sprintf(buf, "select ogr_fid from %s where ogr_fid > 0",
00531                         Map->fInfo.ogr.layer_name);
00532                 db_set_string(&sql, buf);
00533 
00534                 if (db_open_select_cursor
00535                     (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00536                     /* Neither FID nor ogc_fid available, so we try gid */
00537                     G_debug(3,
00538                             "Failed. Now searching for gid column in OGR DB");
00539                     sprintf(buf, "select gid from %s where gid > 0",
00540                             Map->fInfo.ogr.layer_name);
00541                     db_set_string(&sql, buf);
00542 
00543                     if (db_open_select_cursor
00544                         (driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00545                         /* neither FID nor ogc_fid nor ogr_fid nor gid available */
00546                         G_warning(_("All FID tests failed. Neither 'FID' nor 'ogc_fid' "
00547                                    "nor 'ogr_fid' nor 'gid' available in OGR DB table"));
00548                         db_close_database_shutdown_driver(driver);
00549                         return 0;
00550                     }
00551                     else
00552                         GID = 1;
00553                 }
00554                 else
00555                     OGR_FID = 1;
00556             }
00557             else
00558                 OGC_FID = 1;
00559         }
00560         else
00561             FID = 1;
00562 
00563         G_debug(3, "FID: %d, OGC_FID: %d, OGR_FID: %d, GID: %d", FID, OGC_FID,
00564                 OGR_FID, GID);
00565 
00566         db_close_cursor(&cursor);
00567         db_close_database_shutdown_driver(driver);
00568         db_auto_print_errors(1);
00569 
00570         if (FID) {
00571             G_debug(3, "Using FID column in OGR DB");
00572             Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name, "FID",
00573                             Map->fInfo.ogr.dsn, "ogr");
00574         }
00575         else {
00576             if (OGC_FID) {
00577                 G_debug(3, "Using ogc_fid column in OGR DB");
00578                 Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00579                                 "ogc_fid", Map->fInfo.ogr.dsn, "ogr");
00580             }
00581             else {
00582                 if (OGR_FID) {
00583                     G_debug(3, "Using ogr_fid column in OGR DB");
00584                     Vect_add_dblink(dbl, 1, NULL, Map->fInfo.ogr.layer_name,
00585                                     "ogr_fid", Map->fInfo.ogr.dsn, "ogr");
00586                 }
00587                 else {
00588                     if (GID) {
00589                         G_debug(3, "Using gid column in OGR DB");
00590                         Vect_add_dblink(dbl, 1, NULL,
00591                                         Map->fInfo.ogr.layer_name, "gid",
00592                                         Map->fInfo.ogr.dsn, "ogr");
00593                     }
00594                 }
00595             }
00596         }
00597 #endif /* GDAL_VERSION_NUM > 1320 */
00598         return (1);
00599     }
00600     else if (Map->format != GV_FORMAT_NATIVE) {
00601         G_fatal_error(_("Don't know how to read links for format %d"),
00602                       Map->format);
00603     }
00604 
00605     sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00606             Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00607             GRASS_VECT_DBLN_ELEMENT);
00608     G_debug(1, "dbln file: %s", file);
00609 
00610     fd = fopen(file, "r");
00611     if (fd == NULL) {           /* This may be correct, no tables defined */
00612         G_debug(1, "Cannot open vector database definition file");
00613         return (-1);
00614     }
00615 
00616     row = 0;
00617     rule = 0;
00618     while (G_getl2(buf, 2000, fd)) {
00619         row++;
00620         G_chop(buf);
00621         G_debug(1, "dbln: %s", buf);
00622 
00623         c = (char *)strchr(buf, '#');
00624         if (c != NULL)
00625             *c = '\0';
00626 
00627         if (strlen(buf) == 0)
00628             continue;
00629 
00630         ndef = sscanf(buf, "%s %s %s %s %s", fldstr, tab, col, db, drv);
00631 
00632         if (ndef < 2 || (ndef < 5 && rule < 1)) {
00633             G_warning(_("Error in rule on row %d in %s"), row, file);
00634             continue;
00635         }
00636 
00637         /* get field and field name */
00638         fldname = strchr(fldstr, '/');
00639         if (fldname != NULL) {  /* field has name */
00640             fldname[0] = 0;
00641             fldname++;
00642         }
00643         fld = atoi(fldstr);
00644 
00645         Vect_add_dblink(dbl, fld, fldname, tab, col, db, drv);
00646 
00647         G_debug(1,
00648                 "field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
00649                 fld, fldname, tab, col, db, drv);
00650 
00651         rule++;
00652     }
00653     fclose(fd);
00654 
00655     G_debug(1, "Dblinks read");
00656     return (rule);
00657 }
00658 
00667 int Vect_write_dblinks(struct Map_info *Map)
00668 {
00669     int i;
00670     FILE *fd;
00671     char file[GPATH_MAX], buf[GPATH_MAX];
00672     struct dblinks *dbl;
00673 
00674     G_debug(1, "Vect_write_dblinks(): map = %s, mapset = %s", Map->name,
00675             Map->mapset);
00676 
00677     dbl = Map->dblnk;
00678 
00679     sprintf(file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location,
00680             Map->mapset, GRASS_VECT_DIRECTORY, Map->name,
00681             GRASS_VECT_DBLN_ELEMENT);
00682     G_debug(1, "dbln file: %s", file);
00683 
00684     fd = fopen(file, "w");
00685     if (fd == NULL) {           /* This may be correct, no tables defined */
00686         G_warning(_("Unable to open vector database definition file '%s'"),
00687                   file);
00688         return (-1);
00689     }
00690 
00691     for (i = 0; i < dbl->n_fields; i++) {
00692         if (dbl->field[i].name != NULL)
00693             sprintf(buf, "%d/%s", dbl->field[i].number, dbl->field[i].name);
00694         else
00695             sprintf(buf, "%d", dbl->field[i].number);
00696 
00697         fprintf(fd, "%s %s %s %s %s\n", buf, dbl->field[i].table,
00698                 dbl->field[i].key, dbl->field[i].database,
00699                 dbl->field[i].driver);
00700         G_debug(1, "%s %s %s %s %s", buf, dbl->field[i].table,
00701                 dbl->field[i].key, dbl->field[i].database,
00702                 dbl->field[i].driver);
00703     }
00704     fclose(fd);
00705 
00706     G_debug(1, "Dblinks written");
00707     return 0;
00708 }
00709 
00718 char *Vect_subst_var(const char *in, struct Map_info *Map)
00719 {
00720     char *c;
00721     char buf[1000], str[1000];
00722 
00723     G_debug(3, "Vect_subst_var(): in = %s, map = %s, mapset = %s", in,
00724             Map->name, Map->mapset);
00725 
00726     strcpy(str, in);
00727 
00728     strcpy(buf, str);
00729     c = (char *)strstr(buf, "$GISDBASE");
00730     if (c != NULL) {
00731         *c = '\0';
00732         sprintf(str, "%s%s%s", buf, Map->gisdbase, c + 9);
00733     }
00734 
00735     strcpy(buf, str);
00736     c = (char *)strstr(buf, "$LOCATION_NAME");
00737     if (c != NULL) {
00738         *c = '\0';
00739         sprintf(str, "%s%s%s", buf, Map->location, c + 14);
00740     }
00741 
00742     strcpy(buf, str);
00743     c = (char *)strstr(buf, "$MAPSET");
00744     if (c != NULL) {
00745         *c = '\0';
00746         sprintf(str, "%s%s%s", buf, Map->mapset, c + 7);
00747     }
00748 
00749     strcpy(buf, str);
00750     c = (char *)strstr(buf, "$MAP");
00751     if (c != NULL) {
00752         *c = '\0';
00753         sprintf(str, "%s%s%s", buf, Map->name, c + 4);
00754     }
00755 
00756     G_debug(3, "  -> %s", str);
00757     return (G_store(str));
00758 }
00759 
00771 void Vect_set_db_updated(struct Map_info *Map)
00772 {
00773     if (strcmp(Map->mapset, G_mapset()) != 0) {
00774         G_fatal_error(_("Bug: attempt to update map which is not in current mapset"));
00775     }
00776 
00777     Vect_write_dblinks(Map);
00778 }

Generated on Sat Oct 24 03:25:19 2009 for GRASS Programmer's Manual by  doxygen 1.6.1