field.c

Go to the documentation of this file.
00001 /*
00002 ****************************************************************************
00003 *
00004 * MODULE:       Vector library 
00005 *               
00006 * AUTHOR(S):    Original author CERL, probably Dave Gerdes or Mike Higgins.
00007 *               Update to GRASS 5.7 Radim Blazek and David D. Gray.
00008 *
00009 * PURPOSE:      Higher level functions for reading/writing/manipulating vectors.
00010 *
00011 * COPYRIGHT:    (C) 2001 by the GRASS Development Team
00012 *
00013 *               This program is free software under the GNU General Public
00014 *               License (>=v2). Read the file COPYING that comes with GRASS
00015 *               for details.
00016 * TODO: see Vect_read_dblinks; activate auto-FID detection once 
00017 *       OGR_L_GetFIDColumn() is working or solution found if FID not available
00018 *****************************************************************************/
00019 #include <stdlib.h>
00020 #include <stdio.h>
00021 #include <string.h>
00022 #include <grass/glocale.h>
00023 #include <grass/gis.h>
00024 #include <grass/dbmi.h>
00025 #include <grass/Vect.h>
00026 
00027 #include <gdal_version.h> /* needed for FID detection */
00028 
00035 struct dblinks *
00036 Vect_new_dblinks_struct ( void )
00037 {
00038   struct dblinks *p;
00039 
00040   p = (struct dblinks *) G_malloc (sizeof (struct dblinks));
00041 
00042   if (p) {
00043       p->alloc_fields = p->n_fields = 0;
00044       p->field = NULL;
00045   }
00046 
00047   return p;
00048 }
00049 
00056 void
00057 Vect_reset_dblinks ( struct dblinks *p )
00058 {
00059     p->n_fields = 0;
00060 }
00061 
00069 int
00070 Vect_map_add_dblink ( struct Map_info *Map, int number, char *name, char *table, char *key, 
00071                      char *db, char *driver )
00072 {
00073     int ret;
00074 
00075     if (number == 0) {
00076         G_warning (_("Field number must be 1 or greater."));
00077         return -1;
00078     }
00079     
00080     if (Map->mode != GV_MODE_WRITE && Map->mode != GV_MODE_RW) {
00081         G_warning (_("Cannot add database link, map is not opened in WRITE mode."));
00082         return -1;
00083     }
00084     
00085     ret = Vect_add_dblink ( Map->dblnk, number, name, table, key, db, driver );
00086     if ( ret == -1 ) {
00087         G_warning (_("Cannot add database link."));
00088         return -1;
00089     }
00090     /* write it immediately otherwise it is lost if module crashes */
00091     ret = Vect_write_dblinks ( Map );
00092     if ( ret == -1 ) {
00093         G_warning (_("Cannot write database links."));
00094         return -1;
00095     }
00096     return 0;
00097 }
00098 
00105 int
00106 Vect_map_del_dblink ( struct Map_info *Map, int field)
00107 {
00108     int    i, j, ret;
00109     struct dblinks *links;
00110 
00111     G_debug(4, "Vect_map_del_dblink() field = %d", field);
00112     links = Map->dblnk;
00113     
00114     ret = -1;
00115     for (i = 0; i < links->n_fields; i++) {
00116         if ( links->field[i].number == field ) { /* field found */
00117             for (j = i; j < links->n_fields - 1; j++) {
00118                 links->field[j].number = links->field[j+1].number;
00119                 links->field[j].name = links->field[j+1].name;
00120                 links->field[j].table = links->field[j+1].table;
00121                 links->field[j].key = links->field[j+1].key;
00122                 links->field[j].database = links->field[j+1].database;
00123                 links->field[j].driver = links->field[j+1].driver;
00124             }
00125             ret = 0;
00126             links->n_fields--;
00127         }
00128     }
00129 
00130     if ( ret == -1 )
00131         return -1;
00132 
00133     /* write it immediately otherwise it is lost if module crashes */
00134     ret = Vect_write_dblinks ( Map );
00135     if ( ret == -1 ) {
00136         G_warning (_("Cannot write database links."));
00137         return -1;
00138     }
00139 
00140     return 0;
00141 }
00142 
00149 int
00150 Vect_map_check_dblink ( struct Map_info *Map, int field )
00151 {
00152     return Vect_check_dblink ( Map->dblnk, field );
00153 }
00154 
00161 int
00162 Vect_check_dblink ( struct dblinks *p, int field )
00163 {
00164     int i;
00165     
00166     G_debug(3,"Vect_check_dblink: field %d", field);
00167     
00168     for (i = 0; i < p->n_fields; i++) {
00169        if ( p->field[i].number == field ) {
00170            return 1;
00171        }
00172     }
00173     return 0;
00174 }
00175 
00176     
00184 int
00185 Vect_add_dblink ( struct dblinks *p, int number, char *name, char *table, char *key, char *db, char *driver )
00186 {
00187     int ret;
00188     
00189     G_debug (3, "Field number <%d>, name <%s>", number, name);
00190     ret = Vect_check_dblink ( p, number );
00191     if ( ret == 1 ) {
00192          G_warning (_("Field number <%d> or name <%s> already exists"), number, name);
00193          return -1;
00194     }
00195 
00196     if ( p->n_fields == p->alloc_fields ) {
00197        p->alloc_fields += 10;
00198        p->field = ( struct field_info *) G_realloc ( (void *) p->field, 
00199                            p->alloc_fields * sizeof (struct field_info) );
00200     }
00201 
00202     p->field[p->n_fields].number =  number;
00203     
00204     if ( name != NULL ) p->field[p->n_fields].name = G_store ( name );
00205     else  p->field[p->n_fields].name = NULL;
00206     
00207     if ( table != NULL ) p->field[p->n_fields].table = G_store ( table );
00208     else p->field[p->n_fields].table = NULL;
00209     
00210     if ( key != NULL ) p->field[p->n_fields].key = G_store ( key );
00211     else p->field[p->n_fields].key = NULL;
00212     
00213     if ( db != NULL ) p->field[p->n_fields].database = G_store ( db );
00214     else p->field[p->n_fields].database = NULL;
00215     
00216     if ( driver != NULL ) p->field[p->n_fields].driver = G_store ( driver );
00217     else p->field[p->n_fields].driver = NULL;
00218     
00219     p->n_fields++;
00220 
00221     return 0;
00222 }
00223 
00230 struct field_info
00231 *Vect_default_field_info (
00232     struct Map_info *Map,  /* pointer to map structure */               
00233     int  field,    /* category field */
00234     char *field_name, /* field name or NULL */
00235     int  type ) /* how many tables are linked to map: GV_1TABLE / GV_MTABLE */
00236 {
00237     struct field_info *fi;
00238     char buf[1000], buf2[1000];
00239     char *schema;
00240     char *drv, *db;
00241     dbConnection  connection;
00242     
00243     G_debug (1, "Vect_default_field_info(): map = %s field = %d", Map->name, field);
00244     
00245     db_get_connection( &connection );
00246     drv = G__getenv2 ( "DB_DRIVER", G_VAR_MAPSET );
00247     db = G__getenv2 ( "DB_DATABASE", G_VAR_MAPSET );
00248 
00249     G_debug (2, "drv = %s db = %s", drv, db );
00250 
00251     if ( !connection.driverName && !connection.databaseName ) { /* Set default values and create dbf db dir */
00252         G_warning ( _("Default driver / database set to:\n"
00253                     "driver: dbf\ndatabase: $GISDBASE/$LOCATION_NAME/$MAPSET/dbf/") );
00254             
00255         connection.driverName = "dbf";
00256         connection.databaseName = "$GISDBASE/$LOCATION_NAME/$MAPSET/dbf/";
00257         db_set_connection( &connection );
00258         
00259         sprintf ( buf, "%s/%s/%s/dbf", Map->gisdbase, Map->location, Map->mapset );
00260         G__make_mapset_element ( "dbf" );
00261     } else if ( !connection.driverName ) {
00262        G_fatal_error ( _("Default driver is not set") ); 
00263     } else if ( !connection.databaseName ) {
00264        G_fatal_error ( _("Default database is not set") ); 
00265     }
00266     drv = connection.driverName;
00267     db = connection.databaseName;
00268     
00269     fi = (struct field_info *) G_malloc( sizeof(struct field_info) );
00270     
00271     fi->number = field;
00272     if ( field_name != NULL ) fi->name = G_store ( field_name );
00273     else fi->name = NULL;
00274     
00275     /* Table name */
00276     if ( type == GV_1TABLE ) {
00277         sprintf ( buf, "%s", Map->name);
00278     } else {
00279         if ( field_name != NULL && strlen ( field_name ) > 0 )
00280             sprintf ( buf, "%s_%s", Map->name, field_name );
00281         else
00282             sprintf ( buf, "%s_%d", Map->name, field );
00283     }
00284     
00285     schema = connection.schemaName;
00286     if ( schema && strlen(schema) > 0 ) {
00287         sprintf ( buf2, "%s.%s", schema, buf );
00288         fi->table = G_store ( buf2 );
00289     } else { 
00290         fi->table = G_store ( buf );
00291     }
00292     
00293     fi->key = G_store ( "cat" ); /* Should be: id/fid/gfid/... ? */
00294     fi->database = G_store( db );
00295     fi->driver = G_store( drv );
00296 
00297     return (fi);
00298 }
00299 
00307 struct field_info
00308 *Vect_get_dblink (  struct Map_info *Map, int link )
00309 {
00310     struct field_info *fi;
00311 
00312     G_debug (1, "Vect_get_dblink(): link = %d", link);
00313 
00314     if ( link >= Map->dblnk->n_fields ) {
00315         G_warning ( _("Requested dblink %d, maximum link number %d"), link, Map->dblnk->n_fields - 1 );
00316         return NULL;
00317     }
00318 
00319     fi = (struct field_info *) malloc( sizeof(struct field_info) );
00320     fi->number = Map->dblnk->field[link].number;
00321     
00322     if ( Map->dblnk->field[link].name != NULL ) 
00323         fi->name = G_store ( Map->dblnk->field[link].name );
00324     else
00325         fi->name = NULL;
00326     
00327     fi->table = G_store ( Map->dblnk->field[link].table );
00328     fi->key = G_store ( Map->dblnk->field[link].key );
00329     fi->database = Vect_subst_var ( Map->dblnk->field[link].database, Map );
00330     fi->driver = G_store ( Map->dblnk->field[link].driver );
00331 
00332     return fi;
00333 }
00334 
00342 struct field_info
00343 *Vect_get_field (  struct Map_info *Map, int field )
00344 {
00345     int i;
00346     struct field_info *fi = NULL;
00347 
00348     G_debug (1, "Vect_get_field(): field = %d", field);
00349 
00350     for ( i = 0; i < Map->dblnk->n_fields; i++ ) {
00351         if ( Map->dblnk->field[i].number == field ) {
00352             fi = Vect_get_dblink ( Map, i );
00353             break;
00354         }
00355     }
00356             
00357     return fi;
00358 }
00359 
00366 int
00367 Vect_read_dblinks ( struct Map_info *Map )
00368 {
00369     int  ndef;  
00370     FILE *fd;
00371     char file[1024], buf[2001];
00372     char tab[1024], col[1024], db[1024], drv[1024], fldstr[1024], *fldname;
00373     int  fld;
00374     char *c;
00375     int  row, rule;
00376     struct dblinks *dbl;
00377     
00378     G_debug (1, "Vect_read_dblinks(): map = %s, mapset = %s", Map->name, Map->mapset);
00379     
00380     dbl = Map->dblnk;
00381     Vect_reset_dblinks ( dbl );
00382    
00383     G_debug (3, "Searching for FID column in OGR DB");
00384     if ( Map->format == GV_FORMAT_OGR ) {
00385 
00386 #if GDAL_VERSION_NUM > 1320 /* seems to be fixed after 1320 release */
00387         int i, layer, nLayers;
00388         OGRDataSourceH Ogr_ds;
00389         OGRLayerH Ogr_layer=NULL;
00390         OGRFeatureDefnH Ogr_featuredefn;
00391         char ogr_fid_col[1024];
00392 
00393 
00394         G_debug (3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00395 
00396         /* we open the connection to fetch the FID column name */
00397         OGRRegisterAll ();
00398 
00399         /*Data source handle */
00400         Ogr_ds = OGROpen (Map->fInfo.ogr.dsn, FALSE, NULL);
00401         if (Ogr_ds == NULL)
00402            G_fatal_error ("Cannot open OGR data source '%s'", Map->fInfo.ogr.dsn);
00403         Map->fInfo.ogr.ds = Ogr_ds;
00404 
00405         /* Layer number */
00406         layer = -1;
00407         nLayers = OGR_DS_GetLayerCount (Ogr_ds); /* Layers = Maps in OGR DB */
00408 
00409         G_debug (3, "%d layers (maps) found in data source", nLayers);
00410 
00411         G_debug (3, "Trying to open OGR layer: %s", Map->fInfo.ogr.layer_name);
00412         Ogr_layer = OGR_DS_GetLayerByName (Ogr_ds, Map->fInfo.ogr.layer_name);
00413         if (Ogr_layer == NULL) {
00414            OGR_DS_Destroy (Ogr_ds);
00415            G_fatal_error ("Cannot open layer '%s'", Map->fInfo.ogr.layer_name);
00416         }
00417         Ogr_featuredefn = OGR_L_GetLayerDefn (Ogr_layer);
00418         G_debug (3, "layer %s, FID col name: %s", OGR_FD_GetName (Ogr_featuredefn), 
00419                         OGR_L_GetFIDColumn( Ogr_layer ));
00420         Map->fInfo.ogr.layer = Ogr_layer;
00421         G_debug (3, "OGR Map->fInfo.ogr.layer %p opened", Map->fInfo.ogr.layer);
00422 
00423         /* TODO what to do if OGR_L_GetFIDColumn() doesn't return FID name */
00424         sprintf ( ogr_fid_col, "%s", OGR_L_GetFIDColumn( Map->fInfo.ogr.layer ));
00425         G_debug (3, "Using FID column <%s> in OGR DB", ogr_fid_col);
00426         Vect_add_dblink ( dbl, 1, NULL, Map->fInfo.ogr.layer_name, ogr_fid_col, Map->fInfo.ogr.dsn, "ogr") ;
00427 #else
00428         dbDriver *driver;
00429         dbCursor cursor;
00430         dbString sql;
00431         int FID=0, OGC_FID=0, OGR_FID=0, GID=0;
00432 
00433         G_debug (3, "GDAL_VERSION_NUM: %d", GDAL_VERSION_NUM);
00434 
00435         /* FID is not available for all OGR drivers */
00436         db_init_string (&sql);
00437 
00438         driver = db_start_driver_open_database ( "ogr", Map->fInfo.ogr.dsn );
00439 
00440         if ( driver == NULL ) {
00441             G_warning (_("Cannot open OGR DBMI driver."));
00442             return -1;
00443         }
00444 
00445       /* this is a bit stupid, but above FID auto-detection doesn't work yet...: */
00446         db_auto_print_errors(0);
00447         sprintf ( buf, "select FID from %s where FID > 0", Map->fInfo.ogr.layer_name );
00448         db_set_string ( &sql, buf );
00449 
00450         if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00451             /* FID not available, so we try ogc_fid */
00452             G_debug (3, "Failed. Now searching for ogc_fid column in OGR DB");
00453             sprintf ( buf, "select ogc_fid from %s where ogc_fid > 0", Map->fInfo.ogr.layer_name );
00454             db_set_string ( &sql, buf );
00455 
00456             if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00457                 /* Neither FID nor ogc_fid available, so we try ogr_fid */
00458                 G_debug (3, "Failed. Now searching for ogr_fid column in OGR DB");
00459                 sprintf ( buf, "select ogr_fid from %s where ogr_fid > 0", Map->fInfo.ogr.layer_name );
00460                 db_set_string ( &sql, buf );
00461 
00462                 if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00463                    /* Neither FID nor ogc_fid available, so we try gid */
00464                    G_debug (3, "Failed. Now searching for gid column in OGR DB");
00465                    sprintf ( buf, "select gid from %s where gid > 0", Map->fInfo.ogr.layer_name );
00466                    db_set_string ( &sql, buf );
00467 
00468                    if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK) {
00469                       /* neither FID nor ogc_fid nor ogr_fid nor gid available */
00470                       G_warning ("All FID tests failed. Neither 'FID' nor 'ogc_fid' nor 'ogr_fid' nor 'gid' available in OGR DB table");
00471                       db_close_database_shutdown_driver ( driver );
00472                       return 0;
00473                    } else
00474                       GID=1;
00475                 } else
00476                     OGR_FID=1;
00477             } else
00478                 OGC_FID=1;
00479         } else
00480             FID=1;
00481         
00482         G_debug(3,"FID: %d, OGC_FID: %d, OGR_FID: %d, GID: %d",FID, OGC_FID, OGR_FID, GID);
00483 
00484         db_close_cursor(&cursor);
00485         db_close_database_shutdown_driver ( driver );
00486         db_auto_print_errors(1);
00487         
00488         if (FID) {
00489             G_debug (3, "Using FID column in OGR DB");
00490             Vect_add_dblink ( dbl, 1, NULL, Map->fInfo.ogr.layer_name, "FID", Map->fInfo.ogr.dsn, "ogr" ) ;
00491         } else {
00492              if (OGC_FID) {
00493                  G_debug (3, "Using ogc_fid column in OGR DB");
00494                  Vect_add_dblink ( dbl, 1, NULL, Map->fInfo.ogr.layer_name, "ogc_fid", Map->fInfo.ogr.dsn, "ogr" ) ;
00495              } else {
00496                  if (OGR_FID) {
00497                      G_debug (3, "Using ogr_fid column in OGR DB");
00498                      Vect_add_dblink ( dbl, 1, NULL, Map->fInfo.ogr.layer_name, "ogr_fid", Map->fInfo.ogr.dsn, "ogr" ) ;
00499                  } else {
00500                      if (GID) {
00501                         G_debug (3, "Using gid column in OGR DB");
00502                         Vect_add_dblink ( dbl, 1, NULL, Map->fInfo.ogr.layer_name, "gid", Map->fInfo.ogr.dsn, "ogr" ) ;
00503                      }
00504                  }
00505              }
00506         }
00507 #endif /* GDAL_VERSION_NUM > 1320 */
00508         return ( 1 );
00509     } else if ( Map->format != GV_FORMAT_NATIVE ) {
00510         G_fatal_error (_("Don't know how to read links for format %d"), Map->format );
00511     }
00512     
00513     sprintf ( file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location, Map->mapset, GRASS_VECT_DIRECTORY, 
00514                                          Map->name, GRASS_VECT_DBLN_ELEMENT );
00515     G_debug (1, "dbln file: %s", file);
00516 
00517     fd = fopen ( file, "r" );
00518     if ( fd == NULL ) { /* This may be correct, no tables defined */
00519         G_debug ( 1, "Cannot open vector database definition file");
00520         return (-1);
00521     }
00522 
00523     row = 0;
00524     rule = 0;
00525     while ( G_getl2 (buf, 2000, fd) ) {
00526         row++;      
00527         G_chop ( buf ); 
00528         G_debug (1, "dbln: %s", buf);
00529 
00530         c = (char *) strchr ( buf, '#');
00531         if ( c != NULL ) *c = '\0';
00532 
00533         if ( strlen(buf) == 0 ) continue;
00534         
00535         ndef = sscanf ( buf, "%s %s %s %s %s", fldstr, tab, col, db, drv);
00536     
00537         if ( ndef < 2 || (ndef < 5 && rule < 1 ) ) {
00538             G_warning ( _("Error in rule on row %d in %s"), row, file);
00539             continue;
00540         }
00541 
00542         /* get field and field name */
00543         fldname = strchr ( fldstr, '/' );
00544         if ( fldname != NULL ) { /* field has name */
00545             fldname[0] = 0;
00546             fldname++;
00547         }
00548         fld = atoi ( fldstr );
00549         
00550         Vect_add_dblink ( dbl, fld, fldname, tab, col, db, drv );
00551 
00552         G_debug (1, "field = %d name = %s, table = %s, key = %s, database = %s, driver = %s",
00553                      fld, fldname, tab, col, db, drv );
00554 
00555         rule++;
00556     }
00557     fclose (fd);
00558 
00559     G_debug (1, "Dblinks read");
00560     return ( rule );
00561 }
00562 
00569 int
00570 Vect_write_dblinks ( struct Map_info *Map )
00571 {
00572     int    i;   
00573     FILE *fd;
00574     char file[1024], buf[1024];
00575     struct dblinks *dbl;    
00576     
00577     G_debug (1, "Vect_write_dblinks(): map = %s, mapset = %s", Map->name, Map->mapset );
00578     
00579     dbl = Map->dblnk;
00580 
00581     sprintf ( file, "%s/%s/%s/%s/%s/%s", Map->gisdbase, Map->location, Map->mapset, GRASS_VECT_DIRECTORY, 
00582                                          Map->name, GRASS_VECT_DBLN_ELEMENT );
00583     G_debug (1, "dbln file: %s", file);
00584 
00585     fd = fopen ( file, "w" );
00586     if ( fd == NULL ) { /* This may be correct, no tables defined */
00587         G_warning ( "Cannot open vector database definition file: '%s'", file);
00588         return (-1);
00589     }
00590 
00591     for ( i = 0; i < dbl->n_fields; i++ ) {
00592         if ( dbl->field[i].name != NULL )
00593             sprintf ( buf , "%d/%s", dbl->field[i].number, dbl->field[i].name );
00594         else 
00595             sprintf ( buf , "%d", dbl->field[i].number );
00596                     
00597         fprintf ( fd, "%s %s %s %s %s\n", buf, dbl->field[i].table, dbl->field[i].key,
00598                                 dbl->field[i].database, dbl->field[i].driver );
00599         G_debug (1, "%s %s %s %s %s", buf, dbl->field[i].table, dbl->field[i].key,
00600                                 dbl->field[i].database, dbl->field[i].driver );
00601     }
00602     fclose (fd);
00603 
00604     G_debug (1, "Dblinks written");
00605     return 0;
00606 }
00607 
00614 char *
00615 Vect_subst_var ( char *in, struct Map_info *Map )
00616 {
00617     char *c;
00618     char buf[1000], str[1000];
00619     
00620     G_debug (3, "Vect_subst_var(): in = %s, map = %s, mapset = %s", in, Map->name, Map->mapset);
00621     
00622     strcpy ( str, in );
00623     
00624     strcpy ( buf, str );
00625     c = (char *) strstr ( buf, "$GISDBASE" );
00626     if ( c != NULL ) {
00627         *c = '\0';            
00628         sprintf (str, "%s%s%s", buf, Map->gisdbase, c+9);
00629     }
00630 
00631     strcpy ( buf, str );
00632     c = (char *) strstr ( buf, "$LOCATION_NAME" );
00633     if ( c != NULL ) {
00634         *c = '\0';            
00635         sprintf (str, "%s%s%s", buf, Map->location, c+14);
00636     }
00637 
00638     strcpy ( buf, str );
00639     c = (char *) strstr ( buf, "$MAPSET" );
00640     if ( c != NULL ) {
00641         *c = '\0';            
00642         sprintf (str, "%s%s%s", buf, Map->mapset, c+7);
00643     }
00644     
00645     strcpy ( buf, str );
00646     c = (char *) strstr ( buf, "$MAP" );
00647     if ( c != NULL ) {
00648         *c = '\0';            
00649         sprintf (str, "%s%s%s", buf, Map->name, c+4 );
00650     }
00651     
00652     G_debug (3, "  -> %s", str);
00653     return ( G_store(str) );
00654 }
00655 
00662 void Vect_set_db_updated ( struct Map_info *Map )
00663 {
00664     if ( strcmp(Map->mapset,G_mapset() ) != 0 ) {
00665         G_fatal_error ( _("Bug: attempt to update map which is not in current mapset." ) );
00666     }
00667 
00668     Vect_write_dblinks ( Map ) ;
00669 }

Generated on Sun Apr 6 17:32:44 2008 for GRASS by  doxygen 1.5.5