Пример #1
0
/*!
  \brief Free allocated dbIndex

  \param index pointer to dbIndex to be freed
*/
void db_free_index(dbIndex * index)
{
    db_free_string(&index->indexName);
    db_free_string(&index->tableName);
    if (index->numColumns > 0)
	db_free_string_array(index->columnNames, index->numColumns);
    db_init_index(index);
}
Пример #2
0
OGRGRASSLayer::~OGRGRASSLayer()
{
    if ( bCursorOpened ) 
    {
	db_close_cursor ( poCursor);
    }

    if ( poDriver ) 
    {
	StopDbDriver();
    }
    
    if ( pszName ) CPLFree ( pszName );
    if ( poFeatureDefn )
        poFeatureDefn->Release();
    if ( poSRS )
        poSRS->Release();

    if ( pszQuery ) CPLFree ( pszQuery );
    
    if ( paFeatureIndex ) CPLFree ( paFeatureIndex );
    
    if ( poLink ) CPLFree ( poLink );
    
    Vect_destroy_line_struct ( poPoints );
    Vect_destroy_cats_struct ( poCats );

    db_free_string ( poDbString );
    CPLFree ( poDbString );
    CPLFree ( poCursor );

    if ( paSpatialMatch ) CPLFree ( paSpatialMatch );
    if ( paQueryMatch ) CPLFree ( paQueryMatch );
}
Пример #3
0
int Select(double *PartialX, double *PartialY, double *Interp,
           int line_num, dbDriver * driver, char *tab_name)
{
    int more;
    char buf[1024];
    dbString sql;
    dbTable *table;
    dbCursor cursor;
    dbColumn *PartialX_col, *PartialY_col, *Interp_col;
    dbValue *PartialX_value, *PartialY_value, *Interp_value;

    db_init_string(&sql);
    sprintf(buf,
	    "SELECT ID, Interp, X, Y FROM %s WHERE ID=%d",
	    tab_name, line_num);
    db_append_string(&sql, buf);

    if (db_open_select_cursor(driver, &sql, &cursor, DB_SEQUENTIAL) != DB_OK)
	return -1;

    table = db_get_cursor_table(&cursor);

    while (db_fetch(&cursor, DB_NEXT, &more) == DB_OK && more) {

	Interp_col = db_get_table_column(table, 1);
	PartialX_col = db_get_table_column(table, 2);
	PartialY_col = db_get_table_column(table, 3);

	if (db_sqltype_to_Ctype(db_get_column_sqltype(Interp_col)) ==
	    DB_C_TYPE_DOUBLE)
	    Interp_value = db_get_column_value(Interp_col);
	else
	    continue;

	if (db_sqltype_to_Ctype(db_get_column_sqltype(PartialX_col)) ==
	    DB_C_TYPE_DOUBLE)
	    PartialX_value = db_get_column_value(PartialX_col);
	else
	    continue;

	if (db_sqltype_to_Ctype(db_get_column_sqltype(PartialY_col)) ==
	    DB_C_TYPE_DOUBLE)
	    PartialY_value = db_get_column_value(PartialY_col);
	else
	    continue;

	*Interp += db_get_value_double(Interp_value);
	*PartialX += db_get_value_double(PartialX_value);
	*PartialY += db_get_value_double(PartialY_value);
    }
    db_close_cursor(&cursor);
    db_free_string(&sql);
    return DB_OK;
}
Пример #4
0
/*!
  \brief Select one (first) value from table/column for key/id

  \param driver DB driver
  \param tab table name
  \param key key column name
  \param id identifier in key column
  \param col name of column to select the value from
  \param[out] val dbValue to store within

  \return number of selected values
  \return -1 on error
 */
int db_select_value(dbDriver * driver, const char *tab, const char *key,
		    int id, const char *col, dbValue * val)
{
    int more, count;
    char buf[1024];
    dbString stmt;
    dbCursor cursor;
    dbColumn *column;
    dbValue *value;
    dbTable *table;

    if (key == NULL || strlen(key) == 0) {
	G_warning(_("Missing key column name"));
	return -1;
    }

    if (col == NULL || strlen(col) == 0) {
	G_warning(_("Missing column name"));
	return -1;
    }

    G_zero(val, sizeof(dbValue));
    sprintf(buf, "SELECT %s FROM %s WHERE %s = %d\n", col, tab, key, id);
    db_init_string(&stmt);
    db_append_string(&stmt, buf);

    if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
	return (-1);

    table = db_get_cursor_table(&cursor);
    column = db_get_table_column(table, 0);	/* first column */
    value = db_get_column_value(column);

    /* fetch the data */
    count = 0;
    while (1) {
	if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
	    return (-1);

	if (!more)
	    break;
	if (count == 0)
	    db_copy_value(val, value);
	count++;
    }
    db_close_cursor(&cursor);
    db_free_string(&stmt);

    return (count);
}
Пример #5
0
/*!
  \brief Open select cursor

  \return DB_OK on success
  \return DB_FAILED on failure
 */
int db_d_open_select_cursor(void)
{
    dbCursor *cursor;
    int stat;
    dbToken token;
    dbString select;
    int mode;

    /* get the arg(s) */
    db_init_string(&select);
    DB_RECV_STRING(&select);
    DB_RECV_INT(&mode);

    /* create a cursor */
    cursor = (dbCursor *) db_malloc(sizeof(dbCursor));
    if (cursor == NULL)
	return db_get_error_code();
    token = db_new_token((dbAddress) cursor);
    if (token < 0)
	return db_get_error_code();
    db_init_cursor(cursor);

    /* call the procedure */
    stat = db_driver_open_select_cursor(&select, cursor, mode);
    db_free_string(&select);

    /* send the return code */
    if (stat != DB_OK) {
	DB_SEND_FAILURE();
	return DB_OK;
    }
    DB_SEND_SUCCESS();

    /* mark this as a readonly cursor */
    db_set_cursor_type_readonly(cursor);

    /* add this cursor to the cursors managed by the driver state */
    db__add_cursor_to_driver_state(cursor);

    /* results */
    DB_SEND_TOKEN(&token);
    DB_SEND_INT(cursor->type);
    DB_SEND_INT(cursor->mode);
    DB_SEND_TABLE_DEFINITION(cursor->table);
    return DB_OK;
}
Пример #6
0
int UpDate(double partialX, double partialY, double Interp,
	   int line_num, dbDriver * driver, char *tab_name)
{
    char buf[1024];
    dbString sql;
    int ret;

    db_init_string(&sql);
    sprintf(buf,
	    "UPDATE %s SET Interp=%lf, X=%lf, Y=%lf WHERE ID=%d",
	    tab_name, Interp, partialX, partialY, line_num);
    db_append_string(&sql, buf);

    ret = db_execute_immediate(driver, &sql);
    db_free_string(&sql);

    return ret;
}
Пример #7
0
int Insert_Interpolation(double Interp, int line_num, dbDriver * driver,
			 char *tab_name)
{
    char buf[1024];
    dbString sql;
    int ret;

    db_init_string(&sql);
    sprintf(buf, "INSERT INTO %s (ID, Interp)", tab_name);
    db_append_string(&sql, buf);
    sprintf(buf, " VALUES (%d, %lf)", line_num, Interp);
    db_append_string(&sql, buf);

    ret = db_execute_immediate(driver, &sql);
    db_free_string(&sql);

    return ret;
}
Пример #8
0
/*
    Write a vector geometry to the output GRASS vector map.
    Write attributes to table linked to that map. Link vector object to attribute
    table record.
*/
void write_vect( int cat, int skelID, int boneID, int unitID,
		 double *xpnts, double *ypnts, double *zpnts, 
		 int arr_size, int type )
{
    struct line_cats *Cats;
    struct line_pnts *Points;
    char buf[MAXSTR];
    char rgbbuf[12];
    char rgbbuf2[12];
    

    /* copy xyzpnts to Points */
    Points = Vect_new_line_struct();
    Vect_copy_xyz_to_pnts(Points, xpnts, ypnts, zpnts, arr_size);

    /* write database attributes */
    Cats = Vect_new_cats_struct();
    sprintf ( rgbbuf, "%i:%i:%i", RGB[RGBNUM][0], RGB[RGBNUM][1], RGB[RGBNUM][2] );
    sprintf ( rgbbuf2, "%i:%i:%i", RGB[RGB_MAPPER_COLOUR[boneID-1]][0],RGB[RGB_MAPPER_COLOUR[boneID-1]][1], RGB[RGB_MAPPER_COLOUR[boneID-1]][2] );
    sprintf(buf, "insert into %s (cat, skel_id, bone_id, unit_id, GRASSRGB, BONERGB) values(%i,%i,%i,%i,'%s','%s');",
            Fi->table, cat, skelID, boneID, unitID, rgbbuf, rgbbuf2);

    if ( DEBUG ) {
        fprintf ( stderr, "Writing attribute: %s\n", buf );
    }

    db_set_string(&sql, buf);
    if (db_execute_immediate(driver, &sql) != DB_OK) {
	G_fatal_error(_("Unable to insert new record: %s"), db_get_string(&sql));
    }
    db_free_string(&sql);
 
    Vect_cat_set(Cats, 1, cat);

    /* write */
    Vect_write_line(Map, type, Points, Cats);

    Vect_destroy_cats_struct(Cats);
    Vect_destroy_line_struct(Points);
}
Пример #9
0
/*!
  \brief Execute SQL statements

  \return DB_OK on success
  \return DB_FAILED on failure
 */
int db_d_execute_immediate(void)
{
    int stat;
    dbString SQLstatement;

    /* get the arg(s) */
    db_init_string(&SQLstatement);
    DB_RECV_STRING(&SQLstatement);

    /* call the procedure */
    stat = db_driver_execute_immediate(&SQLstatement);
    db_free_string(&SQLstatement);

    /* send the return code */
    if (stat != DB_OK) {
	DB_SEND_FAILURE();
	return DB_OK;
    }
    DB_SEND_SUCCESS();

    /* no results */
    return DB_OK;
}
Пример #10
0
int update(struct Map_info *Map)
{
    int i, *catexst, *cex, upd, fcat;
    char buf1[2000], buf2[2000], left[20], right[20];
    struct field_info *qFi, *Fi;
    dbString stmt;
    dbDriver *driver;

    vstat.dupl = 0;
    vstat.exist = 0;
    vstat.notexist = 0;
    vstat.update = 0;
    vstat.error = 0;

    db_init_string(&stmt);

    /* layer to find table to read from */
    qFi = Vect_get_field(Map, options.qfield);
    if (options.option == O_QUERY && qFi == NULL)
        G_fatal_error(_("Database connection not defined for layer %d. Use v.db.connect first."),
                      options.qfield);
    /* layer to find table to write to */
    if ((Fi = Vect_get_field(Map, options.field)) == NULL)
	G_fatal_error(_("Database connection not defined for layer %d. Use v.db.connect first."),
		      options.field);
    if (qFi) {
      G_debug(3, "Reading from map <%s>, query layer %d (table <%s>): updating table <%s>, column <%s>", 
	      options.name, options.qfield, qFi->table, Fi->table, Fi->key);
    }
    else {
      G_debug(3, "Reading from map <%s>, updating table <%s>, column <%s>", 
	      options.name, Fi->table, Fi->key);
    }

    /* Open driver */
    driver = db_start_driver_open_database(Fi->driver, Fi->database);
    if (driver == NULL) {
	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
		      Fi->database, Fi->driver);
    }
    db_set_error_handler_driver(driver);

    db_begin_transaction(driver);

    /* select existing categories (layer) to array (array is sorted) */
    vstat.select = db_select_int(driver, Fi->table, Fi->key, NULL, &catexst);
    G_debug(3, "Existing categories: %d", vstat.select);
    
    /* create beginning of stmt */
    switch (options.option) {
    case O_CAT:
	sprintf(buf1, "insert into %s ( %s ) values ", Fi->table, Fi->key);
	break;
    case O_COUNT:
    case O_LENGTH:
    case O_AREA:
    case O_QUERY:
    case O_COMPACT:
    case O_FD:
    case O_PERIMETER:
    case O_SLOPE:
    case O_SINUOUS:
    case O_AZIMUTH:
	sprintf(buf1, "update %s set %s =", Fi->table, options.col[0]);
	break;
    case O_COOR:
    case O_START:
    case O_END:
    case O_SIDES:
	sprintf(buf1, "update %s set ", Fi->table);
	break;
    }

    /* update */
    G_message(_("Updating database..."));
    for (i = 0; i < vstat.rcat; i++) {
	G_percent(i, vstat.rcat, 2);

	fcat = Values[i].cat;	
	if (fcat < 0)
	    continue;
	switch (options.option) {
	case O_CAT:
	    sprintf(buf2, "%s ( %d )", buf1, Values[i].cat);
	    break;

	case O_COUNT:
	    sprintf(buf2, "%s %d where %s = %d", buf1, Values[i].count1,
		    Fi->key, Values[i].cat);
	    break;

	case O_LENGTH:
	case O_AREA:
	case O_COMPACT:
	case O_FD:
	case O_PERIMETER:
	case O_SLOPE:
	case O_SINUOUS:
	case O_AZIMUTH:
	    sprintf(buf2, "%s %f where %s = %d", buf1, Values[i].d1, Fi->key,
		    Values[i].cat);
	    break;

	case O_COOR:
	case O_START:
	case O_END:
	    if (Values[i].count1 > 1) {
		G_warning(_("More elements of category %d, nothing loaded to database"),
			  Values[i].cat);
		vstat.dupl++;
		continue;
	    }
	    if (Values[i].count1 < 1) {	/* No points */
		continue;
	    }
	    if (options.col[2]) {
		sprintf(buf2,
			"%s %s = %.15g, %s = %.15g, %s = %.15g where %s = %d",
			buf1, options.col[0], Values[i].d1, options.col[1],
			Values[i].d2, options.col[2], Values[i].d3, Fi->key,
			Values[i].cat);
	    }
	    else {
		sprintf(buf2, "%s %s = %.15g, %s = %.15g  where %s = %d",
			buf1, options.col[0], Values[i].d1, options.col[1],
			Values[i].d2, Fi->key, Values[i].cat);
	    }
	    break;

	case O_SIDES:
	    if (Values[i].count1 == 1) {
		if (Values[i].i1 >= 0)
		    sprintf(left, "%d", Values[i].i1);
		else
		    sprintf(left, "-1");	/* NULL, no area/cat */
	    }
	    else if (Values[i].count1 > 1) {
		sprintf(left, "null");
	    }
	    else {		/* Values[i].count1 == 0 */
		/* It can be OK if the category is assigned to an element
		   type which is not GV_BOUNDARY */
		/* -> TODO: print only if there is boundary with that cat */
		sprintf(left, "null");
	    }

	    if (Values[i].count2 == 1) {
		if (Values[i].i2 >= 0)
		    sprintf(right, "%d", Values[i].i2);
		else
		    sprintf(right, "-1");	/* NULL, no area/cat */
	    }
	    else if (Values[i].count2 > 1) {
		sprintf(right, "null");
	    }
	    else {		/* Values[i].count1 == 0 */
		sprintf(right, "null");
	    }

	    sprintf(buf2, "%s %s = %s, %s = %s  where %s = %d", buf1,
		    options.col[0], left, options.col[1], right, Fi->key,
		    Values[i].cat);

	    break;

	case O_QUERY:
	    if (Values[i].null) {
		sprintf(buf2, "%s null where %s = %d", buf1, Fi->key,
			Values[i].cat);
	    }
	    else {
		switch (vstat.qtype) {
		case (DB_C_TYPE_INT):
		    sprintf(buf2, "%s %d where %s = %d", buf1, Values[i].i1,
			    Fi->key, Values[i].cat);
		    break;
		case (DB_C_TYPE_DOUBLE):
		    sprintf(buf2, "%s %f where %s = %d", buf1, Values[i].d1,
			    Fi->key, Values[i].cat);
		    break;
		case (DB_C_TYPE_STRING):
		    sprintf(buf2, "%s '%s' where %s = %d", buf1,
			    Values[i].str1, Fi->key, Values[i].cat);
		    break;
		case (DB_C_TYPE_DATETIME):
		    sprintf(buf2, "%s '%s' where %s = %d", buf1,
			    Values[i].str1, Fi->key, Values[i].cat);
		    break;
		}
	    }
	}

	G_debug(3, "SQL: %s", buf2);
	db_set_string(&stmt, buf2);

	/* category exist in DB table ? */
	cex = (int *)bsearch((void *)&fcat, catexst, vstat.select, sizeof(int),
			     srch);
	
	if (options.option == O_CAT) {
	    if (cex == NULL) {	/* cat does not exist in DB */
		upd = 1;
		vstat.notexist++;
	    }
	    else {		/* cat exists in DB */
		G_warning(_("Record (cat %d) already exists (not inserted)"),
			  fcat);
		upd = 0;
		vstat.exist++;
	    }
	}
	else {
	    if (cex == NULL) {	/* cat does not exist in DB */
		G_warning(_("Record (cat %d) does not exist (not updated)"),
			  fcat);
		upd = 0;
		vstat.notexist++;
	    }
	    else {		/* cat exists in DB */
		upd = 1;
		vstat.exist++;
	    }
	}

	if (upd == 1) {
	    if (options.sql) {
		fprintf(stdout, "%s\n", db_get_string(&stmt));
	    }
	    else {
		if (db_execute_immediate(driver, &stmt) == DB_OK) {
		    vstat.update++;
		}
		else {
		    vstat.error++;
		}
	    }
	}
    }
    G_percent(1, 1, 1);

    db_commit_transaction(driver);

    G_free(catexst);
    
    db_close_database_shutdown_driver(driver);
    db_free_string(&stmt);

    return 0;
}
Пример #11
0
Файл: main.c Проект: caomw/grass
int main(int argc, char *argv[])
{
    char *p;
    int i, j, k;
    int method, half, use_catno;
    const char *mapset;
    struct GModule *module;
    struct Option *point_opt,	/* point vector */
     *area_opt,			/* area vector */
     *point_type_opt,		/* point type */
     *point_field_opt,		/* point layer */
     *area_field_opt,		/* area layer */
     *method_opt,		/* stats method */
     *point_column_opt,		/* point column for stats */
     *count_column_opt,		/* area column for point count */
     *stats_column_opt,		/* area column for stats result */
     *fs_opt;			/* field separator for printed output */
    struct Flag *print_flag;
    char *fs;
    struct Map_info PIn, AIn;
    int point_type, point_field, area_field;
    struct line_pnts *Points;
    struct line_cats *ACats, *PCats;
    AREA_CAT *Area_cat;
    int pline, ptype, count;
    int area, nareas, nacats, nacatsalloc;
    int ctype, nrec;
    struct field_info *PFi, *AFi;
    dbString stmt;
    dbDriver *Pdriver, *Adriver;
    char buf[2000];
    int update_ok, update_err;
    struct boxlist *List;
    struct bound_box box;
    dbCatValArray cvarr;
    dbColumn *column;
    struct pvalcat
    {
	double dval;
	int catno;
    } *pvalcats;
    int npvalcats, npvalcatsalloc;
    stat_func *statsvalue = NULL;
    double result;

    column = NULL;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("attribute table"));
    G_add_keyword(_("database"));
    G_add_keyword(_("univariate statistics"));
    G_add_keyword(_("zonal statistics"));
    module->description = _("Count points in areas, calculate statistics from point attributes.");

    point_opt = G_define_standard_option(G_OPT_V_INPUT);
    point_opt->key = "points";
    point_opt->description = _("Name of existing vector map with points");
    /* point_opt->guisection = _("Required"); */

    area_opt = G_define_standard_option(G_OPT_V_INPUT);
    area_opt->key = "areas";
    area_opt->description = _("Name of existing vector map with areas");
    /* area_opt->guisection = _("Required"); */

    point_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    point_type_opt->key = "type";
    point_type_opt->options = "point,centroid";
    point_type_opt->answer = "point";
    point_type_opt->label = _("Feature type");
    point_type_opt->required = NO;

    point_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    point_field_opt->key = "player";
    point_field_opt->label = _("Layer number for points map");

    area_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    area_field_opt->key = "alayer";
    area_field_opt->label = _("Layer number for area map");

    method_opt = G_define_option();
    method_opt->key = "method";
    method_opt->type = TYPE_STRING;
    method_opt->required = NO;
    method_opt->multiple = NO;
    p = G_malloc(1024);
    for (i = 0; menu[i].name; i++) {
	if (i)
	    strcat(p, ",");
	else
	    *p = 0;
	strcat(p, menu[i].name);
    }
    method_opt->options = p;
    method_opt->description = _("Method for aggregate statistics");

    point_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    point_column_opt->key = "pcolumn";
    point_column_opt->required = NO;
    point_column_opt->multiple = NO;
    point_column_opt->label =
	_("Column name of points map to use for statistics");
    point_column_opt->description = _("Column of points map must be numeric");

    count_column_opt = G_define_option();
    count_column_opt->key = "ccolumn";
    count_column_opt->type = TYPE_STRING;
    count_column_opt->required = NO;
    count_column_opt->multiple = NO;
    count_column_opt->label = _("Column name to upload points count");
    count_column_opt->description =
	_("Column to hold points count, must be of type integer, will be created if not existing");

    stats_column_opt = G_define_option();
    stats_column_opt->key = "scolumn";
    stats_column_opt->type = TYPE_STRING;
    stats_column_opt->required = NO;
    stats_column_opt->multiple = NO;
    stats_column_opt->label = _("Column name to upload statistics");
    stats_column_opt->description =
	_("Column to hold statistics, must be of type double, will be created if not existing");

    fs_opt = G_define_standard_option(G_OPT_F_SEP);

    print_flag = G_define_flag();
    print_flag->key = 'p';
    print_flag->label =
	_("Print output to stdout, do not update attribute table");
    print_flag->description = _("First column is always area category");

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    point_type = Vect_option_to_types(point_type_opt);

    point_field = atoi(point_field_opt->answer);
    area_field = atoi(area_field_opt->answer);

    if (print_flag->answer)
	/* get field separator */
	    fs = G_option_to_separator(fs_opt);
    else
	    fs = NULL;

    /* check for stats */
    if (method_opt->answer) {
	if (!point_column_opt->answer) {
	    G_fatal_error("Method but no point column selected");
	}
	if (!print_flag->answer && !stats_column_opt->answer)
	    G_fatal_error("Name for stats column is missing");
    }

    if (point_column_opt->answer) {
	if (!method_opt->answer)
	    G_fatal_error("No method for statistics selected");
	if (!print_flag->answer && !stats_column_opt->answer)
	    G_fatal_error("Name for stats column is missing");
    }
    
    /* Open points vector */
    if ((mapset = G_find_vector2(point_opt->answer, "")) == NULL)
	G_fatal_error(_("Vector map <%s> not found"), point_opt->answer);

    Vect_set_open_level(2);
    if (Vect_open_old(&PIn, point_opt->answer, mapset) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), point_opt->answer);

    /* Open areas vector */
    if ((mapset = G_find_vector2(area_opt->answer, "")) == NULL)
	G_fatal_error(_("Vector map <%s> not found"), area_opt->answer);
    if (!print_flag->answer && strcmp(mapset, G_mapset()) != 0)
	G_fatal_error(_("Vector map <%s> is not in user mapset and cannot be updated"),
		      area_opt->answer);

    Vect_set_open_level(2);
    if (Vect_open_old(&AIn, area_opt->answer, mapset) < 0)
	G_fatal_error(_("Unable to open vector map <%s>"), area_opt->answer);

    method = -1;
    use_catno = 0;
    half = 0;
    if (method_opt->answer) {
	/* get the method */
	for (method = 0; (p = menu[method].name); method++)
	    if ((strcmp(p, method_opt->answer) == 0))
		break;
	if (!p) {
	    G_warning(_("<%s=%s> unknown %s"),
		      method_opt->key, method_opt->answer,
		      method_opt->answer);
	    G_usage();
	    exit(EXIT_FAILURE);
	}

	/* establish the statsvalue routine */
	statsvalue = menu[method].method;

	/* category number of lowest/highest value */
	if ((strcmp(menu[method].name, menu[5].name) == 0) ||
	    (strcmp(menu[method].name, menu[7].name) == 0))
	    use_catno = 1;

	G_debug(1, "method: %s, use cat value: %s", menu[method].name,
		(use_catno == 1 ? "yes" : "no"));
    }

    /* Open database driver */
    db_init_string(&stmt);
    Adriver = NULL;

    if (!print_flag->answer) {

	AFi = Vect_get_field(&AIn, area_field);
	if (AFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  area_field);

	Adriver = db_start_driver_open_database(AFi->driver, AFi->database);
	if (Adriver == NULL)
	    G_fatal_error(_("Unable to open database <%s> with driver <%s>"),
			  AFi->database, AFi->driver);

	if (!count_column_opt->answer)
	    G_fatal_error(_("ccolumn is required to upload point counts"));

	/* check if count column exists */
	G_debug(1, "check if count column exists");
	db_get_column(Adriver, AFi->table, count_column_opt->answer, &column);
	if (column) {
	    /* check count column type */
	    if (db_column_Ctype(Adriver, AFi->table, count_column_opt->answer)
		!= DB_C_TYPE_INT)
		G_fatal_error(_("ccolumn must be of type integer"));

	    db_free_column(column);
	    column = NULL;
	}
	else {
	    /* create count column */
	    /* db_add_column() exists but is not implemented,
	     * see lib/db/stubs/add_col.c */
	    sprintf(buf, "alter table %s add column %s integer",
	                    AFi->table, count_column_opt->answer);
	    db_set_string(&stmt, buf);
	    if (db_execute_immediate(Adriver, &stmt) != DB_OK)
		G_fatal_error(_("Unable to add column <%s>"),
			      count_column_opt->answer);
	}

	if (method_opt->answer) {
	    if (!stats_column_opt->answer)
		G_fatal_error(_("scolumn is required to upload point stats"));

	    /* check if stats column exists */
	    G_debug(1, "check if stats column exists");
	    db_get_column(Adriver, AFi->table, stats_column_opt->answer,
			  &column);
	    if (column) {
		/* check stats column type */
		if (db_column_Ctype
		    (Adriver, AFi->table,
		     stats_column_opt->answer) != DB_C_TYPE_DOUBLE)
		    G_fatal_error(_("scolumn must be of type double"));

		db_free_column(column);
		column = NULL;
	    }
	    else {
		/* create stats column */
		/* db_add_column() exists but is not implemented,
		 * see lib/db/stubs/add_col.c */
		sprintf(buf, "alter table %s add column %s double",
				AFi->table, stats_column_opt->answer);
		db_set_string(&stmt, buf);
		if (db_execute_immediate(Adriver, &stmt) != DB_OK)
		    G_fatal_error(_("Unable to add column <%s>"),
				  stats_column_opt->answer);
	    }
	}
    }
    else
	AFi = NULL;

    Pdriver = NULL;
    if (method_opt->answer) {

	G_verbose_message(_("collecting attributes from points vector..."));

	PFi = Vect_get_field(&PIn, point_field);
	if (PFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  point_field);

	Pdriver = db_start_driver_open_database(PFi->driver, PFi->database);
	if (Pdriver == NULL)
	    G_fatal_error(_("Unable to open database <%s> with driver <%s>"),
			  PFi->database, PFi->driver);

	/* check if point column exists */
	db_get_column(Pdriver, PFi->table, point_column_opt->answer, &column);
	if (column) {
	    db_free_column(column);
	    column = NULL;
	}
	else {
	    G_fatal_error(_("Column <%s> not found in table <%s>"),
			  point_column_opt->answer, PFi->table);
	}

	/* Check column type */
	ctype =
	    db_column_Ctype(Pdriver, PFi->table, point_column_opt->answer);

	if (ctype == DB_C_TYPE_INT)
	    half = menu[method].half;
	else if (ctype == DB_C_TYPE_DOUBLE)
	    half = 0;
	else
	    G_fatal_error(_("column for points vector must be numeric"));

	db_CatValArray_init(&cvarr);
	nrec = db_select_CatValArray(Pdriver, PFi->table, PFi->key,
				     point_column_opt->answer, NULL, &cvarr);
	G_debug(1, "selected values = %d", nrec);
	db_close_database_shutdown_driver(Pdriver);
    }

    Points = Vect_new_line_struct();
    ACats = Vect_new_cats_struct();
    PCats = Vect_new_cats_struct();
    List = Vect_new_boxlist(0);

    /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */
    if ((nareas = Vect_get_num_areas(&AIn)) <= 0)
	G_fatal_error("No areas in area input vector");

    nacatsalloc = nareas;
    Area_cat = (AREA_CAT *) G_calloc(nacatsalloc, sizeof(AREA_CAT));

    /* Read all cats from 'area' */
    nacats = 0;
    for (area = 1; area <= nareas; area++) {

	Vect_get_area_cats(&AIn, area, ACats);

	if (ACats->n_cats <= 0)
	    continue;
	for (i = 0; i < ACats->n_cats; i++) {

	    if (ACats->field[i] == area_field) {
		Area_cat[nacats].area_cat = ACats->cat[i];
		Area_cat[nacats].count = 0;
		Area_cat[nacats].nvalues = 0;
		Area_cat[nacats].nalloc = 0;
		nacats++;
		if (nacats >= nacatsalloc) {
		    nacatsalloc += 100;
		    Area_cat =
			(AREA_CAT *) G_realloc(Area_cat,
					       nacatsalloc *
					       sizeof(AREA_CAT));
		}
	    }

	}
    }

    G_debug(1, "%d cats loaded from vector (including duplicates)", nacats);

    /* Sort by category */
    qsort((void *)Area_cat, nacats, sizeof(AREA_CAT), cmp_area);

    /* remove duplicate categories */
    for (i = 1; i < nacats; i++) {
	if (Area_cat[i].area_cat == Area_cat[i - 1].area_cat) {
	    for (j = i; j < nacats - 1; j++) {
		Area_cat[j].area_cat = Area_cat[j + 1].area_cat;
	    }
	    nacats--;
	}
    }

    G_debug(1, "%d cats loaded from vector (unique)", nacats);

    /* Go through all areas in area vector and find points in points vector
     * falling into the area */
    npvalcatsalloc = 10;
    npvalcats = 0;
    pvalcats =
	(struct pvalcat *)G_calloc(npvalcatsalloc, sizeof(struct pvalcat));

    G_message(_("Selecting points for each area..."));
    count = 0;
    for (area = 1; area <= nareas; area++) {
	dbCatVal *catval;

	G_debug(3, "area = %d", area);
	G_percent(area, nareas, 2);

	Vect_get_area_cats(&AIn, area, ACats);

	if (ACats->n_cats <= 0)
	    continue;

	/* select points by box */
	Vect_get_area_box(&AIn, area, &box);
	box.T = PORT_DOUBLE_MAX;
	box.B = -PORT_DOUBLE_MAX;

	Vect_select_lines_by_box(&PIn, &box, point_type, List);
	G_debug(4, "%d points selected by box", List->n_values);

	/* For each point in box check if it is in the area */
	for (i = 0; i < List->n_values; i++) {

	    pline = List->id[i];
	    G_debug(4, "%d: point %d", i, pline);

	    ptype = Vect_read_line(&PIn, Points, PCats, pline);
	    if (!(ptype & point_type))
		continue;

	    /* point in area */
	    if (Vect_point_in_area(Points->x[0], Points->y[0], &AIn, area, &box)) {
		AREA_CAT *area_info, search_ai;

		int tmp_cat;

		/* stats on point column */
		if (method_opt->answer) {
		    npvalcats = 0;
		    tmp_cat = -1;
		    for (j = 0; j < PCats->n_cats; j++) {
			if (PCats->field[j] == point_field) {
			    if (tmp_cat >= 0)
				G_debug(3,
					"More cats found in point layer (point=%d)",
					pline);
			    tmp_cat = PCats->cat[j];

			    /* find cat in array */
			    db_CatValArray_get_value(&cvarr, tmp_cat,
						     &catval);

			    if (catval) {
				pvalcats[npvalcats].catno = tmp_cat;
				switch (cvarr.ctype) {
				case DB_C_TYPE_INT:
				    pvalcats[npvalcats].dval = catval->val.i;
				    npvalcats++;
				    break;

				case DB_C_TYPE_DOUBLE:
				    pvalcats[npvalcats].dval = catval->val.d;
				    npvalcats++;
				    break;
				}
				if (npvalcats >= npvalcatsalloc) {
				    npvalcatsalloc += 10;
				    pvalcats =
					(struct pvalcat *)G_realloc(pvalcats,
								    npvalcatsalloc
								    *
								    sizeof
								    (struct
								     pvalcat));
				}
			    }
			}
		    }
		}

		/* update count for all area cats of given field */
		search_ai.area_cat = -1;
		for (j = 0; j < ACats->n_cats; j++) {
		    if (ACats->field[j] == area_field) {
			if (search_ai.area_cat >= 0)
			    G_debug(3,
				    "More cats found in area layer (area=%d)",
				    area);
			search_ai.area_cat = ACats->cat[j];

			/* find cat in array */
			area_info =
			    (AREA_CAT *) bsearch((void *)&search_ai, Area_cat,
						 nacats, sizeof(AREA_CAT),
						 cmp_area);
			if (area_info->area_cat != search_ai.area_cat)
			    G_fatal_error(_("could not find area category %d"),
					  search_ai.area_cat);

			/* each point is counted once, also if it has
			 * more than one category or no category
			 * OK? */
			area_info->count++;

			if (method_opt->answer) {
			    /* ensure enough space */
			    if (area_info->nvalues + npvalcats >=
				area_info->nalloc) {
				if (area_info->nalloc == 0) {
				    area_info->nalloc = npvalcats + 10;
				    area_info->values =
					(double *)G_calloc(area_info->nalloc,
							   sizeof(double));
				    area_info->cats =
					(int *)G_calloc(area_info->nalloc,
							sizeof(int));
				}
				else
				    area_info->nalloc +=
					area_info->nvalues + npvalcats + 10;
				area_info->values =
				    (double *)G_realloc(area_info->values,
							area_info->nalloc *
							sizeof(double));
				area_info->cats =
				    (int *)G_realloc(area_info->cats,
						     area_info->nalloc *
						     sizeof(int));
			    }
			    for (k = 0; k < npvalcats; k++) {
				area_info->cats[area_info->nvalues] =
				    pvalcats[k].catno;
				area_info->values[area_info->nvalues] =
				    pvalcats[k].dval;
				area_info->nvalues++;
			    }
			}
		    }
		}
		count++;
	    }
	}			/* next point in box */
    }				/* next area */

    G_debug(1, "count = %d", count);

    /* release catval array */
    if (method_opt->answer)
	db_CatValArray_free(&cvarr);

    Vect_close(&PIn);

    /* Update table or print to stdout */
    if (print_flag->answer) {	/* print header */
	fprintf(stdout, "area_cat%scount", fs);
	if (method_opt->answer)
	    fprintf(stdout, "%s%s", fs, menu[method].name);
	fprintf(stdout, "\n");
    }
    else {
	G_message("Updating attributes for area vector...");
	update_err = update_ok = 0;
    }
    if (Adriver)
	db_begin_transaction(Adriver);

    for (i = 0; i < nacats; i++) {
	if (!print_flag->answer)
	    G_percent(i, nacats, 2);

	result = 0;

	if (Area_cat[i].count > 0 && method_opt->answer) {
	    /* get stats */
	    statsvalue(&result, Area_cat[i].values, Area_cat[i].nvalues,
			NULL);

	    if (half)
		result += 0.5;
	    else if (use_catno)
		result = Area_cat[i].cats[(int)result];
	}
	if (print_flag->answer) {
	    fprintf(stdout, "%d%s%d", Area_cat[i].area_cat, fs,
		    Area_cat[i].count);
	    if (method_opt->answer) {
		if (Area_cat[i].count > 0)
		    fprintf(stdout, "%s%.15g", fs, result);
		else
		    fprintf(stdout, "%snull", fs);
	    }
	    fprintf(stdout, "\n");
	}
	else {
	    sprintf(buf, "update %s set %s = %d", AFi->table,
		    count_column_opt->answer, Area_cat[i].count);
	    db_set_string(&stmt, buf);
	    if (method_opt->answer) {
		if (Area_cat[i].count > 0)
		    sprintf(buf, " , %s = %.15g", stats_column_opt->answer,
			    result);
		else
		    sprintf(buf, " , %s = null", stats_column_opt->answer);
		db_append_string(&stmt, buf);
	    }
	    sprintf(buf, " where %s = %d", AFi->key, Area_cat[i].area_cat);
	    db_append_string(&stmt, buf);
	    G_debug(2, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(Adriver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }

	}
    }
    if (Adriver)
	db_commit_transaction(Adriver);

    if (!print_flag->answer) {
	G_percent(nacats, nacats, 2);
	db_close_database_shutdown_driver(Adriver);
	db_free_string(&stmt);
	G_message(_("%d records updated"), update_ok);
	if (update_err > 0)
	    G_message(_("%d update errors"), update_err);

	Vect_set_db_updated(&AIn);
    }

    Vect_close(&AIn);

    G_done_msg(" ");

    exit(EXIT_SUCCESS);
}
Пример #12
0
/*!
   \brief transform 3d vector features to 2d (z-coordinate is omitted)

   \param In input vector
   \param Out output vector
   \param type feature type to be transformed
   \param field layer number
   \param zcolumn attribute column where to store height

   \return number of writen features
   \return -1 on error
 */
int trans3d(struct Map_info *In, struct Map_info *Out, int type,
	    const char *field_name, const char *zcolumn)
{
    int ltype, line;
    int ctype;
    int field;
    
    struct line_pnts *Points;
    struct line_cats *Cats;

    struct field_info *Fi;
    dbDriver *driver;
    dbString stmt;
    char buf[2000];
    int ncats, *cats, cat, *cex;

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    db_init_string(&stmt);

    field = Vect_get_field_number(In, field_name);

    if (zcolumn) {
	Fi = Vect_get_field(Out, field);
	if (!Fi) {
	    G_warning(_("Database connection not defined for layer <%s>"),
		      field_name);
	    return -1;
	}

	driver = db_start_driver_open_database(Fi->driver, Fi->database);
	if (!driver) {
	    G_warning(_("Unable to open database <%s> by driver <%s>"),
		      Fi->database, Fi->driver);
	    return -1;
	}

	/* column type must numeric */
	ctype = db_column_Ctype(driver, Fi->table, zcolumn);
	if (ctype == -1) {
	    G_warning(_("Column <%s> not found in table <%s>"),
		      zcolumn, Fi->table);
	    return -1;
	}
	if (ctype != DB_C_TYPE_INT && ctype != DB_C_TYPE_DOUBLE) {
	    G_warning(_("Column must be numeric"));
	    return -1;
	}

	db_begin_transaction(driver);

	/* select existing categories (layer) to array (array is sorted) */
	ncats = db_select_int(driver, Fi->table, Fi->key, NULL, &cats);
	G_debug(3, "Existing categories: %d", ncats);
    }

    line = 1;
    while (1) {
	ltype = Vect_read_next_line(In, Points, Cats);
	if (ltype == -1) {
	    G_warning(_("Unable to read vector map"));
	    return -1;
	}
	if (ltype == -2) {	/* EOF */
	    break;
	}

	if (G_verbose() > G_verbose_min() && (line - 1) % 1000 == 0) {
	    fprintf(stderr, "%7d\b\b\b\b\b\b\b", (line - 1));
	}

	if (!(ltype & type))
	    continue;

	if (field != -1 && !Vect_cat_get(Cats, field, &cat))
	    continue;

	/* get first cat */
	if (cat == -1) {
	    G_warning(_("Feature id %d has no category - skipping"), line);
	}
	else if (Cats->n_cats > 1) {
	    G_warning(_("Feature id %d has more categories. "
			"Using category %d."), line, field, cat);
	}

	if (zcolumn && ltype == GV_POINT && cat > -1) {
	    /* category exist in table ? */
	    cex = (int *)bsearch((void *)&cat, cats, ncats, sizeof(int),
				 srch);

	    /* store height to the attribute table */
	    if (ctype == DB_C_TYPE_INT)
		sprintf(buf, "update %s set %s = %d where cat = %d",
			Fi->table, zcolumn, (int)Points->z[0], cat);
	    else		/* double */
		sprintf(buf, "update %s set %s = %.8f where cat = %d",
			Fi->table, zcolumn, Points->z[0], cat);

	    G_debug(3, "SQL: %s", buf);
	    db_set_string(&stmt, buf);

	    if (cex) {
		if (db_execute_immediate(driver, &stmt) == DB_OK) {
		    /* TODO */
		}
	    }
	    else {		/* cat does not exist in table */
		G_warning(_("Record (cat %d) does not exist (not updated)"),
			  cat);
	    }
	}

	Vect_write_line(Out, ltype, Points, Cats);
	line++;
    }

    if (G_verbose() > G_verbose_min())
	fprintf(stderr, "\r");

    if (zcolumn) {
	db_commit_transaction(driver);

	G_free(cats);

	db_close_database_shutdown_driver(driver);
	db_free_string(&stmt);
    }

    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return line - 1;
}
Пример #13
0
/*!
  \brief Select pairs key/value to array, values are sorted by key (must be integer)

  \param driver DB driver
  \param tab table name
  \param key key column name
  \param col value column name
  \param[out] cvarr dbCatValArray to store within

  \return number of selected values
  \return -1 on error
 */
int db_select_CatValArray(dbDriver * driver, const char *tab, const char *key,
			  const char *col, const char *where,
			  dbCatValArray * cvarr)
{
    int i, type, more, nrows;
    char buf[1024];
    dbString stmt;
    dbCursor cursor;
    dbColumn *column;
    dbValue *value;
    dbTable *table;

    G_debug(3, "db_select_CatValArray ()");

    if (key == NULL || strlen(key) == 0) {
	G_warning(_("Missing key column name"));
	return -1;
    }

    if (col == NULL || strlen(col) == 0) {
	G_warning(_("Missing column name"));
	return -1;
    }
    db_init_string(&stmt);

    sprintf(buf, "SELECT %s, %s FROM %s", key, col, tab);
    db_set_string(&stmt, buf);

    if (where != NULL && strlen(where) > 0) {
	db_append_string(&stmt, " WHERE ");
	db_append_string(&stmt, where);
    }

    G_debug(3, "  SQL: %s", db_get_string(&stmt));

    if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
	return (-1);

    nrows = db_get_num_rows(&cursor);
    G_debug(3, "  %d rows selected", nrows);
    if (nrows < 0) {
	G_warning(_("Unable select records from table <%s>"), tab);
	db_close_cursor(&cursor);
	db_free_string(&stmt);
	return -1;
    }

    db_CatValArray_alloc(cvarr, nrows);

    table = db_get_cursor_table(&cursor);

    /* Check if key column is integer */
    column = db_get_table_column(table, 0);
    type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
    G_debug(3, "  key type = %d", type);

    if (type != DB_C_TYPE_INT) {
	G_warning(_("Key column type is not integer"));
	db_close_cursor(&cursor);
	db_free_string(&stmt);
	return -1;
    }

    column = db_get_table_column(table, 1);
    type = db_sqltype_to_Ctype(db_get_column_sqltype(column));
    G_debug(3, "  col type = %d", type);

    /*
       if ( type != DB_C_TYPE_INT && type != DB_C_TYPE_DOUBLE ) {
       G_fatal_error ( "Column type not supported by db_select_to_array()" );
       }
     */

    cvarr->ctype = type;

    /* fetch the data */
    for (i = 0; i < nrows; i++) {
	if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
	    return (-1);

	column = db_get_table_column(table, 0);	/* first column */
	value = db_get_column_value(column);
	cvarr->value[i].cat = db_get_value_int(value);

	column = db_get_table_column(table, 1);
	value = db_get_column_value(column);
	cvarr->value[i].isNull = value->isNull;
	switch (type) {
	case (DB_C_TYPE_INT):
	    if (value->isNull)
		cvarr->value[i].val.i = 0;
	    else
		cvarr->value[i].val.i = db_get_value_int(value);
	    break;

	case (DB_C_TYPE_DOUBLE):
	    if (value->isNull)
		cvarr->value[i].val.d = 0.0;
	    else
		cvarr->value[i].val.d = db_get_value_double(value);
	    break;

	case (DB_C_TYPE_STRING):
	    cvarr->value[i].val.s = (dbString *) malloc(sizeof(dbString));
	    db_init_string(cvarr->value[i].val.s);

	    if (!(value->isNull))
		db_set_string(cvarr->value[i].val.s,
			      db_get_value_string(value));
	    break;

	case (DB_C_TYPE_DATETIME):
	    cvarr->value[i].val.t =
		(dbDateTime *) calloc(1, sizeof(dbDateTime));

	    if (!(value->isNull))
		memcpy(cvarr->value[i].val.t, &(value->t),
		       sizeof(dbDateTime));
	    break;

	default:
	    return (-1);
	}
    }
    cvarr->n_values = nrows;

    db_close_cursor(&cursor);
    db_free_string(&stmt);

    db_CatValArray_sort(cvarr);

    return (nrows);
}
Пример #14
0
int db__driver_create_table(dbTable * table)
{
    int col, ncols;
    dbColumn *column;
    const char *colname;
    int sqltype;
    char buf[500];
    PGresult *res;
    dbString sql;
    dbConnection connection;

    G_debug(3, "db__driver_create_table()");

    init_error();

    db_init_string(&sql);

    /* db_table_to_sql ( table, &sql ); */

    db_set_string(&sql, "create table ");
    db_append_string(&sql, db_get_table_name(table));
    db_append_string(&sql, " ( ");

    ncols = db_get_table_number_of_columns(table);

    for (col = 0; col < ncols; col++) {
	column = db_get_table_column(table, col);
	colname = db_get_column_name(column);
	sqltype = db_get_column_sqltype(column);

	G_debug(3, "%s (%s)", colname, db_sqltype_name(sqltype));

	if (col > 0)
	    db_append_string(&sql, ", ");
	db_append_string(&sql, colname);
	db_append_string(&sql, " ");
	switch (sqltype) {
	case DB_SQL_TYPE_CHARACTER:
	    sprintf(buf, "varchar(%d)", db_get_column_length(column));
	    db_append_string(&sql, buf);
	    break;
	case DB_SQL_TYPE_TEXT:
	    db_append_string(&sql, "text");
	    break;

	case DB_SQL_TYPE_SMALLINT:
	    db_append_string(&sql, "smallint");
	    break;
	case DB_SQL_TYPE_INTEGER:
	    db_append_string(&sql, "integer");
	    break;

	case DB_SQL_TYPE_REAL:
	    db_append_string(&sql, "real");
	    break;

	    /* TODO: better numeric types */
	case DB_SQL_TYPE_DOUBLE_PRECISION:
	case DB_SQL_TYPE_DECIMAL:
	case DB_SQL_TYPE_NUMERIC:
	case DB_SQL_TYPE_INTERVAL:
	    db_append_string(&sql, "double precision");
	    break;

	case DB_SQL_TYPE_DATE:
	    db_append_string(&sql, "date");
	    break;
	case DB_SQL_TYPE_TIME:
	    db_append_string(&sql, "time");
	    break;
	case DB_SQL_TYPE_TIMESTAMP:
	    db_append_string(&sql, "timestamp");
	    break;

	default:
	    G_warning("Unknown column type (%s)", colname);
	    return DB_FAILED;
	}
    }
    db_append_string(&sql, " )");


    G_debug(3, " SQL: %s", db_get_string(&sql));

    res = PQexec(pg_conn, db_get_string(&sql));

    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
	append_error("Cannot create table:\n");
	append_error(db_get_string(&sql));
	append_error("\n");
	append_error(PQerrorMessage(pg_conn));
	report_error();
	PQclear(res);
	db_free_string(&sql);
	return DB_FAILED;
    }

    PQclear(res);

    /* Grant privileges */
    db_get_connection(&connection);

    db_set_string(&sql, "grant select on ");
    db_append_string(&sql, db_get_table_name(table));
    db_append_string(&sql, " to public");

    if (connection.group) {
	db_append_string(&sql, ", group ");
	db_append_string(&sql, connection.group);
    }

    G_debug(3, " SQL: %s", db_get_string(&sql));

    res = PQexec(pg_conn, db_get_string(&sql));

    if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
	append_error("Cannot grant select on table:\n");
	append_error(db_get_string(&sql));
	append_error("\n");
	append_error(PQerrorMessage(pg_conn));
	report_error();
	PQclear(res);
	db_free_string(&sql);
	return DB_FAILED;
    }

    PQclear(res);
    db_free_string(&sql);

    return DB_OK;
}
Пример #15
0
/*!
  \brief Select array of ordered integers from table/column

  \param driver DB driver
  \param tab table name
  \param col column name
  \param where where statement
  \param[out] pval array of ordered integer values

  \return number of selected values
  \return -1 on error
*/
int db_select_int(dbDriver * driver, const char *tab, const char *col,
		  const char *where, int **pval)
{
    int type, more, alloc, count;
    int *val;
    char buf[1024];
    const char *sval;
    dbString stmt;
    dbCursor cursor;
    dbColumn *column;
    dbValue *value;
    dbTable *table;

    G_debug(3, "db_select_int()");

    if (col == NULL || strlen(col) == 0) {
	G_warning(_("Missing column name"));
	return -1;
    }

    /* allocate */
    alloc = 1000;
    val = (int *)G_malloc(alloc * sizeof(int));

    if (where == NULL || strlen(where) == 0)
	G_snprintf(buf, 1023, "SELECT %s FROM %s", col, tab);
    else
	G_snprintf(buf, 1023, "SELECT %s FROM %s WHERE %s", col, tab, where);

    G_debug(3, "  SQL: %s", buf);

    db_init_string(&stmt);
    db_append_string(&stmt, buf);

    if (db_open_select_cursor(driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
	return (-1);

    table = db_get_cursor_table(&cursor);
    column = db_get_table_column(table, 0);	/* first column */
    if (column == NULL) {
	return -1;
    }
    value = db_get_column_value(column);
    type = db_get_column_sqltype(column);
    type = db_sqltype_to_Ctype(type);

    /* fetch the data */
    count = 0;
    while (1) {
	if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
	    return (-1);

	if (!more)
	    break;

	if (count == alloc) {
	    alloc += 1000;
	    val = (int *)G_realloc(val, alloc * sizeof(int));
	}

	switch (type) {
	case (DB_C_TYPE_INT):
	    val[count] = db_get_value_int(value);
	    break;
	case (DB_C_TYPE_STRING):
	    sval = db_get_value_string(value);
	    val[count] = atoi(sval);
	    break;
	case (DB_C_TYPE_DOUBLE):
	    val[count] = (int)db_get_value_double(value);
	    break;
	default:
	    return (-1);
	}
	count++;
    }

    db_close_cursor(&cursor);
    db_free_string(&stmt);

    qsort((void *)val, count, sizeof(int), cmp);

    *pval = val;

    return (count);
}
Пример #16
0
/*!
  \brief Free dbHandle structure
  
  \param handle pointer to dbHandle
*/
void db_free_handle(dbHandle * handle)
{
    db_free_string(&handle->dbName);
    db_free_string(&handle->dbSchema);
}
Пример #17
0
int write_line(struct Map_info *Map, int type, struct line_pnts *Points)
{
    int i, field, cat, ret;
    static int first_form = 1;
    char *form;
    struct line_cats *Cats;
    struct field_info *Fi;
    dbString html;

    Cats = Vect_new_cats_struct();
    db_init_string(&html);

    cat = var_geti(VAR_CAT);
    if (var_geti(VAR_CAT_MODE) != CAT_MODE_NO && cat > 0 &&
	var_geti(VAR_FIELD) > 0) {
	Vect_cat_set(Cats, var_geti(VAR_FIELD), cat);

	G_debug(2, "write field = %d cat = %d", var_geti(VAR_FIELD),
		var_geti(VAR_CAT));

	if (cat_max_get(var_geti(VAR_FIELD)) < var_geti(VAR_CAT)) {
	    cat_max_set(var_geti(VAR_FIELD), var_geti(VAR_CAT));
	}
    }

    ret = Vect_write_line(Map, type, Points, Cats);

    for (i = 0; i < Vect_get_num_updated_lines(Map); i++)
	G_debug(2, "Updated line: %d", Vect_get_updated_line(Map, i));

    for (i = 0; i < Vect_get_num_updated_nodes(Map); i++)
	G_debug(2, "Updated node: %d", Vect_get_updated_node(Map, i));

    /* Reset category (this automatically resets cat for next not used) */
    var_seti(VAR_FIELD, var_geti(VAR_FIELD));

    if (var_geti(VAR_CAT_MODE) != CAT_MODE_NO && var_geti(VAR_INSERT) &&
	cat > 0) {
	G_debug(2, "Insert new record");
	db_set_string(&html, "<HTML><HEAD><TITLE>");
	db_append_string(&html, _("Form"));
	db_append_string(&html, "</TITLE><BODY>");

	field = var_geti(VAR_FIELD);
	ret = new_record(field, cat);
	if (ret == -1) {
	    return -1;
	}
	else if (ret == 0) {
	    db_append_string(&html, _("New record was created.<BR>"));
	}
	else {			/* record already existed */
	    db_append_string(&html,
			     _("Record for this category already existed.<BR>"));
	}

	/* Open form */
	Fi = Vect_get_field(Map, field);
	if (Fi == NULL) {
	    return -1;
	}
	F_generate(Fi->driver, Fi->database, Fi->table, Fi->key, cat, NULL,
		   NULL, F_EDIT, F_HTML, &form);
	db_append_string(&html, form);
	db_append_string(&html, "</BODY></HTML>");

	/* Note: F_open() must be run first time with closed monitor, otherwise next
	 *        attempt to open driver hangs until form child process is killed */
	if (first_form)
	    driver_close();
	F_clear();
	F_open(_("Attributes"), db_get_string(&html));
	if (first_form) {
	    driver_open();
	    first_form = 0;
	}

	G_free(form);
	db_free_string(&html);

    }

    return 0;
}
Пример #18
0
void QgsGrassVectorMapLayer::load()
{
  clear();

  if ( !mMap )
  {
    return;
  }

  // Attributes are not loaded for topo layers in which case field == 0
  if ( mField == 0 )
  {
    return;
  }

  QgsDebugMsg( QString( "cidxFieldIndex() = %1 cidxFieldNumCats() = %2" ).arg( cidxFieldIndex() ).arg( cidxFieldNumCats() ) );

  mFieldInfo = Vect_get_field( mMap->map(), mField ); // should work also with field = 0

  if ( !mFieldInfo )
  {
    QgsDebugMsg( "No field info -> no attribute table" );
  }
  else
  {
    QgsDebugMsg( "Field info found -> open database" );

    QFileInfo di( mMap->grassObject().mapsetPath() + "/vector/" + mMap->grassObject().name() + "/dbln" );
    mLastLoaded = di.lastModified();

    QString error;
    dbDriver *databaseDriver = openDriver( error );

    if ( !databaseDriver || !error.isEmpty() )
    {
      QgsDebugMsg( error );
    }
    else
    {
      QgsDebugMsg( "Database opened -> open select cursor" );
      QgsGrass::lock(); // not sure if lock is necessary
      dbString dbstr;
      db_init_string( &dbstr );
      db_set_string( &dbstr, ( char * )"select * from " );
      db_append_string( &dbstr, mFieldInfo->table );

      QgsDebugMsg( QString( "SQL: %1" ).arg( db_get_string( &dbstr ) ) );
      dbCursor databaseCursor;
      if ( db_open_select_cursor( databaseDriver, &dbstr, &databaseCursor, DB_SCROLL ) != DB_OK )
      {
        db_close_database_shutdown_driver( databaseDriver );
        QgsGrass::warning( "Cannot select attributes from table '" + QString( mFieldInfo->table ) + "'" );
      }
      else
      {
#ifdef QGISDEBUG
        int nRecords = db_get_num_rows( &databaseCursor );
        QgsDebugMsg( QString( "Number of records: %1" ).arg( nRecords ) );
#endif

        dbTable  *databaseTable = db_get_cursor_table( &databaseCursor );
        int nColumns = db_get_table_number_of_columns( databaseTable );

        // Read columns' description
        for ( int i = 0; i < nColumns; i++ )
        {
          QPair<double, double> minMax( DBL_MAX, -DBL_MAX );

          dbColumn *column = db_get_table_column( databaseTable, i );

          int ctype = db_sqltype_to_Ctype( db_get_column_sqltype( column ) );
          QVariant::Type qtype = QVariant::String; //default to string
          QgsDebugMsg( QString( "column = %1 ctype = %2" ).arg( db_get_column_name( column ) ).arg( ctype ) );

          QString ctypeStr;
          switch ( ctype )
          {
            case DB_C_TYPE_INT:
              ctypeStr = QStringLiteral( "integer" );
              qtype = QVariant::Int;
              break;
            case DB_C_TYPE_DOUBLE:
              ctypeStr = QStringLiteral( "double" );
              qtype = QVariant::Double;
              break;
            case DB_C_TYPE_STRING:
              ctypeStr = QStringLiteral( "string" );
              qtype = QVariant::String;
              break;
            case DB_C_TYPE_DATETIME:
              ctypeStr = QStringLiteral( "datetime" );
              qtype = QVariant::String;
              break;
          }
          mTableFields.append( QgsField( db_get_column_name( column ), qtype, ctypeStr,
                                         db_get_column_length( column ), db_get_column_precision( column ) ) );
          mMinMax << minMax;
          if ( G_strcasecmp( db_get_column_name( column ), mFieldInfo->key ) == 0 )
          {
            mKeyColumn = i;
          }
        }

        if ( mKeyColumn < 0 )
        {
          mTableFields.clear();
          QgsGrass::warning( QObject::tr( "Key column '%1' not found in the table '%2'" ).arg( mFieldInfo->key, mFieldInfo->table ) );
        }
        else
        {
          mHasTable = true;
          // Read attributes to the memory
          for ( ;; )
          {
            int more;

            if ( db_fetch( &databaseCursor, DB_NEXT, &more ) != DB_OK )
            {
              QgsDebugMsg( "Cannot fetch DB record" );
              break;
            }
            if ( !more )
            {
              break; // no more records
            }

            // Check cat value
            dbColumn *column = db_get_table_column( databaseTable, mKeyColumn );
            dbValue *value = db_get_column_value( column );

            if ( db_test_value_isnull( value ) )
            {
              continue;
            }
            int cat = db_get_value_int( value );
            if ( cat < 0 )
            {
              continue;
            }

            QList<QVariant> values;
            for ( int i = 0; i < nColumns; i++ )
            {
              column = db_get_table_column( databaseTable, i );
              int sqltype = db_get_column_sqltype( column );
              int ctype = db_sqltype_to_Ctype( sqltype );
              value = db_get_column_value( column );
              db_convert_value_to_string( value, sqltype, &dbstr );

              QgsDebugMsgLevel( QString( "column = %1 value = %2" ).arg( db_get_column_name( column ), db_get_string( &dbstr ) ), 3 );

              QVariant variant;
              if ( !db_test_value_isnull( value ) )
              {
                int iv;
                double dv;
                //layer.mAttributes[layer.nAttributes].values[i] = strdup( db_get_string( &dbstr ) );
                switch ( ctype )
                {
                  case DB_C_TYPE_INT:
                    iv = db_get_value_int( value );
                    variant = QVariant( iv );
                    mMinMax[i].first = std::min( mMinMax[i].first, ( double )iv );
                    mMinMax[i].second = std::min( mMinMax[i].second, ( double )iv );
                    break;
                  case DB_C_TYPE_DOUBLE:
                    dv = db_get_value_double( value );
                    variant = QVariant( dv );
                    mMinMax[i].first = std::min( mMinMax[i].first, dv );
                    mMinMax[i].second = std::min( mMinMax[i].second, dv );
                    break;
                  case DB_C_TYPE_STRING:
                    // Store as byte array so that codec may be used later
                    variant = QVariant( QByteArray( db_get_value_string( value ) ) );
                    break;
                  case DB_C_TYPE_DATETIME:
                    variant = QVariant( QByteArray( db_get_string( &dbstr ) ) );
                    break;
                  default:
                    variant = QVariant( QByteArray( db_get_string( &dbstr ) ) );
                }
              }
              QgsDebugMsgLevel( QString( "column = %1 variant = %2" ).arg( db_get_column_name( column ), variant.toString() ), 3 );
              values << variant;
            }
            mAttributes.insert( cat, values );
          }
        }
        mValid = true;
        db_close_cursor( &databaseCursor );
        db_close_database_shutdown_driver( databaseDriver );
        db_free_string( &dbstr );

        QgsDebugMsg( QString( "mTableFields.size = %1" ).arg( mTableFields.size() ) );
        QgsDebugMsg( QString( "number of attributes = %1" ).arg( mAttributes.size() ) );
      }
      QgsGrass::unlock();
    }
  }

  // Add cat if no attribute fields exist (otherwise qgis crashes)
  if ( mTableFields.size() == 0 )
  {
    mKeyColumn = 0;
    mTableFields.append( QgsField( QStringLiteral( "cat" ), QVariant::Int, QStringLiteral( "integer" ) ) );
    QPair<double, double> minMax( 0, 0 );

    if ( cidxFieldIndex() >= 0 )
    {
      int ncats, cat, type, id;

      ncats = Vect_cidx_get_num_cats_by_index( mMap->map(), cidxFieldIndex() );

      if ( ncats > 0 )
      {
        Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), 0, &cat, &type, &id );
        minMax.first = cat;

        Vect_cidx_get_cat_by_index( mMap->map(), cidxFieldIndex(), ncats - 1, &cat, &type, &id );
        minMax.second = cat;
      }
    }
    mMinMax << minMax;
  }
  mFields = mTableFields;
  mAttributeFields = mTableFields;

  QgsDebugMsg( QString( "layer loaded mTableFields.size() = %1 mAttributes.size() = %2" ).arg( mTableFields.size() ).arg( mAttributes.size() ) );
  mValid = true;
}
Пример #19
0
int main(int argc, char *argv[])
{
    int i, j, nlines, type, field, cat;
    int fd;

    /* struct Categories RCats; *//* TODO */
    struct Cell_head window;
    RASTER_MAP_TYPE out_type;
    CELL *cell;
    DCELL *dcell;
    double drow, dcol;
    char buf[2000];
    struct Option *vect_opt, *rast_opt, *field_opt, *col_opt, *where_opt;
    int Cache_size;
    struct order *cache;
    int cur_row;
    struct GModule *module;

    struct Map_info Map;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int point;
    int point_cnt;		/* number of points in cache */
    int outside_cnt;		/* points outside region */
    int nocat_cnt;		/* points inside region but without category */
    int dupl_cnt;		/* duplicate categories */
    struct bound_box box;

    int *catexst, *cex;
    struct field_info *Fi;
    dbString stmt;
    dbDriver *driver;
    int select, norec_cnt, update_cnt, upderr_cnt, col_type;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("raster"));
    G_add_keyword(_("position"));
    G_add_keyword(_("querying"));
    G_add_keyword(_("attribute table"));
    module->description =
	_("Uploads raster values at positions of vector points to the table.");

    vect_opt = G_define_standard_option(G_OPT_V_INPUT);
    vect_opt->key = "vector";
    vect_opt->description =
	_("Name of input vector points map for which to edit attribute table");

    rast_opt = G_define_standard_option(G_OPT_R_INPUT);
    rast_opt->key = "raster";
    rast_opt->description = _("Name of existing raster map to be queried");

    field_opt = G_define_standard_option(G_OPT_V_FIELD);

    col_opt = G_define_option();
    col_opt->key = "column";
    col_opt->type = TYPE_STRING;
    col_opt->required = YES;
    col_opt->description =
	_("Column name (will be updated by raster values)");

    where_opt = G_define_standard_option(G_OPT_DB_WHERE);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);


    field = atoi(field_opt->answer);

    db_init_string(&stmt);
    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();

    G_get_window(&window);
    Vect_region_box(&window, &box);	/* T and B set to +/- PORT_DOUBLE_MAX */

    /* Open vector */
    Vect_set_open_level(2);
    Vect_open_old(&Map, vect_opt->answer, "");

    Fi = Vect_get_field(&Map, field);
    if (Fi == NULL)
	G_fatal_error(_("Database connection not defined for layer %d"),
		      field);

    /* Open driver */
    driver = db_start_driver_open_database(Fi->driver, Fi->database);
    if (driver == NULL) {
	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
		      Fi->database, Fi->driver);
    }

    /* Open raster */
    fd = Rast_open_old(rast_opt->answer, "");

    out_type = Rast_get_map_type(fd);

    /* TODO: Later possibly category labels */
    /* 
       if ( Rast_read_cats (name, "", &RCats) < 0 )
       G_fatal_error ( "Cannot read category file");
     */

    /* Check column type */
    col_type = db_column_Ctype(driver, Fi->table, col_opt->answer);

    if (col_type == -1)
	G_fatal_error(_("Column <%s> not found"), col_opt->answer);

    if (col_type != DB_C_TYPE_INT && col_type != DB_C_TYPE_DOUBLE)
	G_fatal_error(_("Column type not supported"));

    if (out_type == CELL_TYPE && col_type == DB_C_TYPE_DOUBLE)
	G_warning(_("Raster type is integer and column type is float"));

    if (out_type != CELL_TYPE && col_type == DB_C_TYPE_INT)
	G_warning(_("Raster type is float and column type is integer, some data lost!!"));

    /* Read vector points to cache */
    Cache_size = Vect_get_num_primitives(&Map, GV_POINT);
    /* Note: Some space may be wasted (outside region or no category) */

    cache = (struct order *)G_calloc(Cache_size, sizeof(struct order));

    point_cnt = outside_cnt = nocat_cnt = 0;

    nlines = Vect_get_num_lines(&Map);

    G_debug(1, "Reading %d vector features fom map", nlines);

    for (i = 1; i <= nlines; i++) {
	type = Vect_read_line(&Map, Points, Cats, i);
	G_debug(4, "line = %d type = %d", i, type);

	/* check type */
	if (!(type & GV_POINT))
	    continue;		/* Points only */

	/* check region */
	if (!Vect_point_in_box(Points->x[0], Points->y[0], 0.0, &box)) {
	    outside_cnt++;
	    continue;
	}

	Vect_cat_get(Cats, field, &cat);
	if (cat < 0) {		/* no category of given field */
	    nocat_cnt++;
	    continue;
	}

	G_debug(4, "    cat = %d", cat);

	/* Add point to cache */
	drow = Rast_northing_to_row(Points->y[0], &window);
	dcol = Rast_easting_to_col(Points->x[0], &window);

	/* a special case.
	 *   if north falls at southern edge, or east falls on eastern edge,
	 *   the point will appear outside the window.
	 *   So, for these edges, bring the point inside the window
	 */
	if (drow == window.rows)
	    drow--;
	if (dcol == window.cols)
	    dcol--;

	cache[point_cnt].row = (int)drow;
	cache[point_cnt].col = (int)dcol;
	cache[point_cnt].cat = cat;
	cache[point_cnt].count = 1;
	point_cnt++;
    }

    Vect_set_db_updated(&Map);
    Vect_hist_command(&Map);
    Vect_close(&Map);

    G_debug(1, "Read %d vector points", point_cnt);
    /* Cache may contain duplicate categories, sort by cat, find and remove duplicates 
     * and recalc count and decrease point_cnt  */
    qsort(cache, point_cnt, sizeof(struct order), by_cat);

    G_debug(1, "Points are sorted, starting duplicate removal loop");

    for (i = 0, j = 1; j < point_cnt; j++)
	if (cache[i].cat != cache[j].cat)
	    cache[++i] = cache[j];
	else
	    cache[i].count++;
    point_cnt = i + 1;

    G_debug(1, "%d vector points left after removal of duplicates",
	    point_cnt);

    /* Report number of points not used */
    if (outside_cnt)
	G_warning(_("%d points outside current region were skipped"),
		  outside_cnt);

    if (nocat_cnt)
	G_warning(_("%d points without category were skipped"), nocat_cnt);

    /* Sort cache by current region row */
    qsort(cache, point_cnt, sizeof(struct order), by_row);

    /* Allocate space for raster row */
    if (out_type == CELL_TYPE)
	cell = Rast_allocate_c_buf();
    else
	dcell = Rast_allocate_d_buf();

    /* Extract raster values from file and store in cache */
    G_debug(1, "Extracting raster values");

    cur_row = -1;

    for (point = 0; point < point_cnt; point++) {
	if (cache[point].count > 1)
	    continue;		/* duplicate cats */

	if (cur_row != cache[point].row) {
	    if (out_type == CELL_TYPE)
		Rast_get_c_row(fd, cell, cache[point].row);
	    else
		Rast_get_d_row(fd, dcell, cache[point].row);
	}
	cur_row = cache[point].row;

	if (out_type == CELL_TYPE) {
	    cache[point].value = cell[cache[point].col];
	}
	else {
	    cache[point].dvalue = dcell[cache[point].col];
	}
    }				/* point loop */

    /* Update table from cache */
    G_debug(1, "Updating db table");

    /* select existing categories to array (array is sorted) */
    select = db_select_int(driver, Fi->table, Fi->key, NULL, &catexst);

    db_begin_transaction(driver);

    norec_cnt = update_cnt = upderr_cnt = dupl_cnt = 0;

    for (point = 0; point < point_cnt; point++) {
	if (cache[point].count > 1) {
	    G_warning(_("More points (%d) of category %d, value set to 'NULL'"),
		      cache[point].count, cache[point].cat);
	    dupl_cnt++;
	}

	/* category exist in DB ? */
	cex =
	    (int *)bsearch((void *)&(cache[point].cat), catexst, select,
			   sizeof(int), srch_cat);
	if (cex == NULL) {	/* cat does not exist in DB */
	    norec_cnt++;
	    G_warning(_("No record for category %d in table <%s>"),
		      cache[point].cat, Fi->table);
	    continue;
	}

	sprintf(buf, "update %s set %s = ", Fi->table, col_opt->answer);

	db_set_string(&stmt, buf);

	if (out_type == CELL_TYPE) {
	    if (cache[point].count > 1 ||
		Rast_is_c_null_value(&cache[point].value)) {
		sprintf(buf, "NULL");
	    }
	    else {
		sprintf(buf, "%d ", cache[point].value);
	    }
	}
	else {			/* FCELL or DCELL */
	    if (cache[point].count > 1 ||
		Rast_is_d_null_value(&cache[point].dvalue)) {
		sprintf(buf, "NULL");
	    }
	    else {
		sprintf(buf, "%.10f", cache[point].dvalue);
	    }
	}
	db_append_string(&stmt, buf);

	sprintf(buf, " where %s = %d", Fi->key, cache[point].cat);
	db_append_string(&stmt, buf);
	/* user provides where condition: */
	if (where_opt->answer) {
	    sprintf(buf, " AND %s", where_opt->answer);
	    db_append_string(&stmt, buf);
	}
	G_debug(3, db_get_string(&stmt));

	/* Update table */
	if (db_execute_immediate(driver, &stmt) == DB_OK) {
	    update_cnt++;
	}
	else {
	    upderr_cnt++;
	}
    }

    G_debug(1, "Committing DB transaction");
    db_commit_transaction(driver);
    G_free(catexst);
    db_close_database_shutdown_driver(driver);
    db_free_string(&stmt);

    /* Report */
    G_message(_("%d categories loaded from table"), select);
    G_message(_("%d categories loaded from vector"), point_cnt);
    G_message(_("%d categories from vector missing in table"), norec_cnt);
    G_message(_("%d duplicate categories in vector"), dupl_cnt);
    if (!where_opt->answer)
	G_message(_("%d records updated"), update_cnt);
    G_message(_("%d update errors"), upderr_cnt);

    exit(EXIT_SUCCESS);
}
Пример #20
0
int db__driver_create_table(dbTable * table)
{
    int col, ncols;
    dbColumn *column;
    const char *colname;
    int sqltype;
    char buf[500];
    dbString sql;

    /* dbConnection conn_par; */

    G_debug(3, "db__driver_create_table()");

    init_error();

    db_init_string(&sql);

    db_set_string(&sql, "CREATE TABLE ");
    db_append_string(&sql, db_get_table_name(table));
    db_append_string(&sql, " ( ");

    ncols = db_get_table_number_of_columns(table);

    for (col = 0; col < ncols; col++) {
	column = db_get_table_column(table, col);
	colname = db_get_column_name(column);
	sqltype = db_get_column_sqltype(column);

	G_debug(3, "%s (%s)", colname, db_sqltype_name(sqltype));

	if (col > 0)
	    db_append_string(&sql, ", ");
	db_append_string(&sql, colname);
	db_append_string(&sql, " ");
	switch (sqltype) {
	case DB_SQL_TYPE_SMALLINT:
	    db_append_string(&sql, "SMALLINT");
	    break;
	case DB_SQL_TYPE_INTEGER:
	    db_append_string(&sql, "INT");
	    break;

	case DB_SQL_TYPE_REAL:
	    db_append_string(&sql, "FLOAT");
	    break;

	    /* TODO: better numeric types */
	case DB_SQL_TYPE_DOUBLE_PRECISION:
	case DB_SQL_TYPE_DECIMAL:
	case DB_SQL_TYPE_NUMERIC:
	case DB_SQL_TYPE_INTERVAL:
	    db_append_string(&sql, "DOUBLE");
	    break;

	    /* GRASS does not distinguish TIMESTAMP and DATETIME */
	    /*
	       case DB_SQL_TYPE_DATETIME|DB_DATETIME_MASK:
	       db_append_string ( &sql, "DATETIME");
	       break;
	     */
	case DB_SQL_TYPE_TIMESTAMP:
	    /* db_append_string ( &sql, "TIMESTAMP"); */
	    db_append_string(&sql, "DATETIME");
	    break;

	case DB_SQL_TYPE_DATE:
	    db_append_string(&sql, "DATE");
	    break;
	case DB_SQL_TYPE_TIME:
	    db_append_string(&sql, "TIME");
	    break;

	case DB_SQL_TYPE_CHARACTER:
	    sprintf(buf, "VARCHAR(%d)", db_get_column_length(column));
	    db_append_string(&sql, buf);
	    break;
	case DB_SQL_TYPE_TEXT:
	    db_append_string(&sql, "TEXT");
	    break;

	default:
	    G_warning("Unknown column type (%s)", colname);
	    return DB_FAILED;
	}
    }
    db_append_string(&sql, " )");

    G_debug(3, " SQL: %s", db_get_string(&sql));

    if (mysql_query(connection, db_get_string(&sql)) != 0) {
	append_error("Cannot create table:\n");
	append_error(db_get_string(&sql));
	append_error("\n");
	append_error(mysql_error(connection));
	report_error();
	db_free_string(&sql);
	return DB_FAILED;
    }

    /* Grant privileges */

    /*
     * 1) MySQL does not support user groups but it is possible 
     *    to specify list of users. 
     * 2) Only root can grant privileges.
     */
    /*
       db_get_connection(&conn_par);

       if ( conn_par.group ) 
       {
       db_set_string ( &sql, "GRANT SELECT ON on " );
       db_append_string ( &sql, db_get_table_name ( table ) );
       db_append_string ( &sql, " TO " );
       db_append_string ( &sql, conn_par.group );

       G_debug (3, " SQL: %s", db_get_string(&sql) );

       if ( mysql_query ( connection, db_get_string(&sql) ) != 0 )
       {
       G_warning ( "Cannot grant select on table: \n%s\n%s",
       db_get_string(&sql), mysql_error(connection) );
       }
       }
     */

    db_free_string(&sql);

    return DB_OK;
}
Пример #21
0
int display_attr(struct Map_info *Map, int type, char *attrcol,
		 struct cat_list *Clist, LATTR *lattr, int chcat)
{
    int i, ltype, more;
    struct line_pnts *Points;
    struct line_cats *Cats;
    int cat;
    char buf[2000];
    struct field_info *fi;
    dbDriver *driver;
    dbString stmt, valstr, text;
    dbCursor cursor;
    dbTable *table;
    dbColumn *column;

    G_debug(2, "attr()");

    if (attrcol == NULL || *attrcol == '\0') {
	G_fatal_error(_("attrcol not specified, cannot display attributes"));
    }

    Points = Vect_new_line_struct();
    Cats = Vect_new_cats_struct();
    db_init_string(&stmt);
    db_init_string(&valstr);
    db_init_string(&text);

    fi = Vect_get_field(Map, lattr->field);
    if (fi == NULL)
	return 1;

    driver = db_start_driver_open_database(fi->driver, fi->database);
    if (driver == NULL)
	G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
		      fi->database,
		      fi->driver);

    Vect_rewind(Map);
    while (1) {
	ltype = Vect_read_next_line(Map, Points, Cats);
	if (ltype == -1)
	    G_fatal_error(_("Unable to read vector map"));
	else if (ltype == -2)		/* EOF */
	    break;

	if (!(type & ltype) && !((type & GV_AREA) && (ltype & GV_CENTROID)))
	    continue;		/* used for both lines and labels */

	D_RGB_color(lattr->color.R, lattr->color.G, lattr->color.B);
	D_text_size(lattr->size, lattr->size);
	if (lattr->font)
	    D_font(lattr->font);
	if (lattr->enc)
	    D_encoding(lattr->enc);

	if (chcat) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field &&
		    Vect_cat_in_cat_list(Cats->cat[i], Clist)) {
		    found = 1;
		    break;
		}
	    }
	    if (!found)
		continue;
	}
	else if (Clist->field > 0) {
	    int found = 0;

	    for (i = 0; i < Cats->n_cats; i++) {
		if (Cats->field[i] == Clist->field) {
		    found = 1;
		    break;
		}
	    }
	    /* lines with no category will be displayed */
	    if (Cats->n_cats > 0 && !found)
		continue;
	}

	if (Vect_cat_get(Cats, lattr->field, &cat)) {
	    int ncats = 0;

	    /* Read attribute from db */
	    db_free_string(&text);
	    for (i = 0; i < Cats->n_cats; i++) {
		int nrows;

		if (Cats->field[i] != lattr->field)
		    continue;
		db_init_string(&stmt);
		sprintf(buf, "select %s from %s where %s = %d", attrcol,
			fi->table, fi->key, Cats->cat[i]);
		G_debug(2, "SQL: %s", buf);
		db_append_string(&stmt, buf);

		if (db_open_select_cursor
		    (driver, &stmt, &cursor, DB_SEQUENTIAL) != DB_OK)
		    G_fatal_error(_("Unable to open select cursor: '%s'"),
				  db_get_string(&stmt));

		nrows = db_get_num_rows(&cursor);

		if (ncats > 0)
		    db_append_string(&text, "/");

		if (nrows > 0) {
		    table = db_get_cursor_table(&cursor);
		    column = db_get_table_column(table, 0);	/* first column */

		    if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK)
			continue;
		    db_convert_column_value_to_string(column, &valstr);

		    db_append_string(&text, db_get_string(&valstr));
		}
		else {
		    G_warning(_("No attribute found for cat %d: %s"), cat,
			      db_get_string(&stmt));
		}

		db_close_cursor(&cursor);
		ncats++;
	    }

	    show_label_line(Points, ltype, lattr, db_get_string(&text));
	}
    }

    db_close_database_shutdown_driver(driver);
    Vect_destroy_line_struct(Points);
    Vect_destroy_cats_struct(Cats);

    return 0;
}
Пример #22
0
/*
    Create GRASS vector output map.
    Create attribute table.
    Calculate geometries and write them into the output map.
    Calculate attributes and write them into the output map's attribute table.
*/
void writeMap()
{
    int i, j;
    
    double xlength, ylength, zlength;
    double length, flatLength, bailLength;
    double xoffset, yoffset, zoffset;
    double xys[12];
    int ratio;
    double zRatio;
       
    /* attributes to be written to output map */
    int boneID;
    int skelID;
    int unitID;
    int oldID;
    int cat;
    
    char *organization;
    
    char buf[MAXSTR];
   
    
    
    if ( numPoints < 2 ) {
        G_fatal_error ("Less than two valid measurement points in input file");
    }
    

    G_message (_("Constructing geometries for %i valid points:"), numPoints );
    
    /* CREATE OUTPUT VECTOR MAP */
    
    if (Vect_legal_filename(output->answer) < 0) {
	G_fatal_error(_("Use '%s' option to change vector map name"), output->key);
    }
    
    Map = (struct Map_info *) G_malloc (sizeof ( struct Map_info ) );
    if (Vect_open_new(Map, output->answer, WITH_Z) < 0) {
	G_fatal_error(_("Unable to create vector map <%s>"), output->answer);
    }

    Vect_set_map_name(Map, output->answer);

    Vect_hist_command(Map);    
  
    if ((organization = getenv("GRASS_ORGANIZATION"))) {
	Vect_set_organization(Map, organization);
    } else {
	Vect_set_organization(Map, "UNKNOWN ORGANIZATION");
    }
    Vect_set_date(Map, G_date());
    Vect_set_person(Map, G_whoami());
    Vect_set_map_date(Map, "");
    Vect_set_scale(Map, 2400);
    Vect_set_comment(Map, "");
    Vect_set_zone(Map, 0);
    Vect_set_thresh(Map, 0.0);
    
    
    /* START DBMS INTERFACE */
    
    /* prepare strings for use in db_* calls */
    db_init_string(&sql);
 	
    /* start default database driver */
    Fi = Vect_default_field_info(Map, 1, NULL, GV_1TABLE);
    driver = db_start_driver_open_database(Fi->driver,Vect_subst_var(Fi->database, Map));
    if (driver == NULL) {
	Vect_delete(output->answer);
        G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			      Vect_subst_var(Fi->database, Map), Fi->driver);
    }
    
    /* create attribute table */
    db_begin_transaction ( driver );
    sprintf(buf, "create table %s (cat integer, skel_id integer, bone_id integer, unit_id integer, GRASSRGB varchar(11),BONERGB varchar(11));",
                  Fi->table);
    
    if ( DEBUG ) {
        fprintf ( stderr, "Creating attribute table: %s\n", buf );
    }
    
    db_set_string(&sql, buf);
    if (db_execute_immediate(driver, &sql) != DB_OK) {
        Vect_delete(output->answer);
	G_fatal_error(_("Unable to create attribute table: %s"), db_get_string(&sql));
    }
        
    if (db_grant_on_table
	(driver, output->answer, DB_PRIV_SELECT, DB_GROUP | DB_PUBLIC) != DB_OK) {
	Vect_delete(output->answer);
	G_fatal_error(_("Unable to grant privileges on table <%s>"), output->answer);
    }
    
    if (db_create_index2(driver, output->answer, "cat") != DB_OK) {
	G_warning(_("Unable to create index for table <%s>, key <%s>"), output->answer, "cat");
    }

    /* link vector map to attribute table */
    if (Vect_map_add_dblink(Map, 1, NULL, Fi->table, "cat", Fi->database, Fi->driver) ) {
        Vect_delete(output->answer);
	G_fatal_error(_("Unable to add database link for vector map <%s>"), Vect_get_full_name(Map));
    }
            
    
    /* PROCESS POINTS AND WRITE GEOMETRIES */
    /* Now process point measurements and write geometries into output vector map. */    
    /* At this stage, the global points array has an even number of valid points. */
    oldID = pointTable[0].SKEL_ID;
    unitID = 1;
    cat = 0;
    for ( i = 0; i < numPoints; i = i + 2 ) {
        /* This boneID is a generalized ID that does not differentiate 
	   between start and end measurement. */
        boneID = (int) pointTable[i+1].BONE_ID / 2;
        skelID = pointTable[i+1].SKEL_ID;

	/* get coordinates for top and bottom of bone */
        ax = pointTable[i].X;
        ay = pointTable[i].Y;
        az = pointTable[i].Z;
	
        bx = pointTable[i+1].X;
        by = pointTable[i+1].Y;
        bz = pointTable[i+1].Z;
	
        /* get vector lengths */
        xlength = fabs (ax - bx);
        ylength = fabs (ay - by);
        zlength = fabs (az - bz);
		
        /* get real length */
        length = sqrt ( (xlength*xlength) + (ylength*ylength) + (zlength*zlength) );
		
        /* get length in x/y plane */
        flatLength = sqrt ( (xlength*xlength) + (ylength*ylength) );
	
        /* determine ratio for triangles, depending on bone type */
        ratio = 12; /* default */
	for ( j = 0; j < NUM_RATIOS; j ++ ) {
	    if ( boneID == RATIO_ID[j] ) {
	        ratio = RATIO_VAL[j];
	    }
	}
			
	/* get bail length */
	bailLength = (double) ( length / (double) ratio);
	
        /* calculate bail offsets from top point (one bail is mirror of the other) */
        xoffset = (bailLength * ylength) / flatLength;
        yoffset = ( (bailLength * xlength) / flatLength ) * (-1);
        zoffset = 0;
						
        xys[0]= ax + xoffset;
        xys[1]= ay + yoffset;
        xys[2]= az + zoffset;
        xys[6]= ax - xoffset;
        xys[7]= ay - yoffset;
        xys[8]= az - zoffset;		
			
        /* get 3rd axis offsets */
        zRatio = (zlength/ratio) / flatLength;
        xoffset = xlength * zRatio;
        yoffset = ylength * zRatio;
        zoffset = (flatLength/ratio) * (-1);
	
        xys[3]= ax + xoffset;
        xys[4]= ay + yoffset;
        xys[5]= az + zoffset;
        xys[9]= ax - xoffset;
        xys[10]= ay - yoffset;
        xys[11]= az - zoffset;
	
        /* Increase unit ID by "1", if we have another skeleton ID */
        if ( oldID != pointTable[i+1].SKEL_ID ) {
            unitID ++;
            oldID = pointTable[i+1].SKEL_ID;
	    /* switch to next colour for next geometry */
            RGBNUM ++;
            if ( RGBNUM == RGBMAX ) {
                RGBNUM = 0;
            }	    
        }
	
	/* write geometries */
        if ( MODE == MODE_DARTS ) {
            writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 6 );
	    cat ++;
            writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 9 );
	    cat ++;
        }	
        if ( MODE == MODE_LINES ) {
            writeLine ( cat, skelID, boneID, unitID );
	    cat ++;
        }
        if ( MODE == MODE_PLANES_H ) {
	    writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 6 );
	    cat ++;
	}
        if ( MODE == MODE_PLANES_V ) {
	    writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 9 );
	    cat ++;
        }
	if ( MODE == MODE_POINTS ) {
            writePoints ( cat, skelID, boneID, unitID );	
	    cat = cat + 2;
	}
	if ( MODE == MODE_PYRAMIDS ) {
            writeTriangle ( cat, skelID, boneID, unitID, xys, 0, 3 );
	    cat ++;
            writeTriangle ( cat, skelID, boneID, unitID, xys, 3, 6 );
	    cat ++;
            writeTriangle ( cat, skelID, boneID, unitID, xys, 6, 9 );
	    cat ++;
            writeTriangle ( cat, skelID, boneID, unitID, xys, 9, 0 );
	    cat ++;
            writeSquare ( cat, skelID, boneID, unitID, xys );	
	    cat ++;
        }
	
	/* switch to next colour for bone colouring */
	RGBNUM_BONE ++;
        if ( RGBNUM_BONE == RGBMAX ) {
            RGBNUM_BONE = 0;
        }
	
	G_percent ( i, numPoints - 2, 1 );	    
	
     }
     fprintf ( stdout, "\n" );
    
    /* commit DBMS actions */
    db_commit_transaction(driver);
    db_close_database_shutdown_driver(driver);
    
    if (!Vect_build(Map)) {
        G_warning("Building topology failed");
    }
    
    Vect_close(Map);  
    db_free_string(&sql);
}
Пример #23
0
int write_attributes(dbDriver *driver, int cat, const struct field_info *Fi,
                     OGRLayerH Ogr_layer, OGRFeatureH Ogr_feature)
{
    int j, ogrfieldnum;
    char buf[2000];
    int ncol, sqltype, ctype, ogrtype, more;
    const char *fidcol, *colname;
    dbTable *table;
    dbString dbstring;
    dbColumn *column;
    dbCursor cursor;
    dbValue *value;

    OGRFieldDefnH hFieldDefn;

    G_debug(3, "write_attributes(): cat = %d", cat);

    if (cat < 0) {
        G_warning(_("Feature without category of layer %d"), Fi->number);
        return 0;
    }

    db_init_string(&dbstring);

    /* read & set attributes */
    sprintf(buf, "SELECT * FROM %s WHERE %s = %d", Fi->table, Fi->key,
            cat);
    G_debug(4, "SQL: %s", buf);
    db_set_string(&dbstring, buf);

    /* select data */
    if (db_open_select_cursor(driver, &dbstring, &cursor, DB_SEQUENTIAL) != DB_OK) {
        G_fatal_error(_("Unable to select attributes for category %d"),
                      cat);
    }

    if (db_fetch(&cursor, DB_NEXT, &more) != DB_OK) {
        G_fatal_error(_("Unable to fetch data from table <%s>"),
                      Fi->table);
    }

    if (!more) {
        G_warning(_("No database record for category %d, "
                    "no attributes will be written"),
                  cat);
        return -1;
    }

    fidcol = OGR_L_GetFIDColumn(Ogr_layer);

    table = db_get_cursor_table(&cursor);
    ncol = db_get_table_number_of_columns(table);
    for (j = 0; j < ncol; j++) {
        column = db_get_table_column(table, j);
        colname = db_get_column_name(column);
        if (fidcol && *fidcol && strcmp(colname, fidcol) == 0) {
            /* skip fid column */
            continue;
        }
        value = db_get_column_value(column);
        /* for debug only */
        db_convert_column_value_to_string(column, &dbstring);
        G_debug(2, "col %d : val = %s", j,
                db_get_string(&dbstring));

        sqltype = db_get_column_sqltype(column);
        ctype = db_sqltype_to_Ctype(sqltype);
        ogrtype = sqltype_to_ogrtype(sqltype);
        G_debug(2, "  colctype = %d", ctype);

        ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
        if (ogrfieldnum < 0) {
            /* create field if not exists */
            hFieldDefn = OGR_Fld_Create(colname, ogrtype);
            if (OGR_L_CreateField(Ogr_layer, hFieldDefn, TRUE) != OGRERR_NONE)
                G_warning(_("Unable to create field <%s>"), colname);
            ogrfieldnum = OGR_F_GetFieldIndex(Ogr_feature, colname);
        }

        /* Reset */
        OGR_F_UnsetField(Ogr_feature, ogrfieldnum);

        /* prevent writing NULL values */
        if (!db_test_value_isnull(value)) {
            switch (ctype) {
            case DB_C_TYPE_INT:
                OGR_F_SetFieldInteger(Ogr_feature, ogrfieldnum,
                                      db_get_value_int(value));
                break;
            case DB_C_TYPE_DOUBLE:
                OGR_F_SetFieldDouble(Ogr_feature, ogrfieldnum,
                                     db_get_value_double(value));
                break;
            case DB_C_TYPE_STRING:
                OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
                                     db_get_value_string(value));
                break;
            case DB_C_TYPE_DATETIME:
                db_convert_column_value_to_string(column,
                                                  &dbstring);
                OGR_F_SetFieldString(Ogr_feature, ogrfieldnum,
                                     db_get_string(&dbstring));
                break;
            }
        }
    }

    db_close_cursor (&cursor);

    db_free_string(&dbstring);

    return 1;
}
Пример #24
0
int main(int argc, char *argv[])
{
    int i, j, k;
    int print_as_matrix;	/* only for all */
    int all;			/* calculate from each to each within the threshold */
    struct GModule *module;
    struct Option *from_opt, *to_opt, *from_type_opt, *to_type_opt,
	*from_field_opt, *to_field_opt;
    struct Option *out_opt, *max_opt, *min_opt, *table_opt;
    struct Option *upload_opt, *column_opt, *to_column_opt;
    struct Flag *print_flag, *all_flag;
    struct Map_info From, To, Out, *Outp;
    int from_type, to_type, from_field, to_field;
    double max, min;
    double *max_step;
    int n_max_steps, curr_step;
    struct line_pnts *FPoints, *TPoints;
    struct line_cats *FCats, *TCats;
    NEAR *Near, *near;
    int anear;			/* allocated space, used only for all */
    UPLOAD *Upload;		/* zero terminated */
    int ftype, fcat, tcat, count;
    int nfrom, nto, nfcats, fline, tline, tseg, tarea, area, isle, nisles;
    double tx, ty, tz, dist, talong, tmp_tx, tmp_ty, tmp_tz, tmp_dist,
	tmp_talong;
    struct field_info *Fi, *toFi;
    dbString stmt, dbstr;
    dbDriver *driver, *to_driver;
    int *catexist, ncatexist, *cex;
    char buf1[2000], buf2[2000];
    int update_ok, update_err, update_exist, update_notexist, update_dupl,
	update_notfound;
    struct boxlist *List;
    struct bound_box box;
    dbCatValArray cvarr;
    dbColumn *column;

    all = 0;
    print_as_matrix = 0;
    column = NULL;

    G_gisinit(argv[0]);

    module = G_define_module();
    G_add_keyword(_("vector"));
    G_add_keyword(_("database"));
    G_add_keyword(_("attribute table"));
    module->description =
	_("Finds the nearest element in vector map 'to' for elements in vector map 'from'.");

    from_opt = G_define_standard_option(G_OPT_V_INPUT);
    from_opt->key = "from";
    from_opt->description = _("Name of existing vector map (from)");
    from_opt->guisection = _("From");

    from_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    from_field_opt->key = "from_layer";
    from_field_opt->label = _("Layer number or name (from)");
    from_field_opt->guisection = _("From");

    from_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    from_type_opt->key = "from_type";
    from_type_opt->options = "point,centroid";
    from_type_opt->answer = "point";
    from_type_opt->label = _("Feature type (from)");
    from_type_opt->guisection = _("From");

    to_opt = G_define_standard_option(G_OPT_V_INPUT);
    to_opt->key = "to";
    to_opt->description = _("Name of existing vector map (to)");
    to_opt->guisection = _("To");

    to_field_opt = G_define_standard_option(G_OPT_V_FIELD);
    to_field_opt->key = "to_layer";
    to_field_opt->label = _("Layer number or name (to)");
    to_field_opt->guisection = _("To");

    to_type_opt = G_define_standard_option(G_OPT_V_TYPE);
    to_type_opt->key = "to_type";
    to_type_opt->options = "point,line,boundary,centroid,area";
    to_type_opt->answer = "point,line,area";
    to_type_opt->label = _("Feature type (to)");
    to_type_opt->guisection = _("To");

    out_opt = G_define_standard_option(G_OPT_V_OUTPUT);
    out_opt->key = "output";
    out_opt->required = NO;
    out_opt->description = _("Name for output vector map containing lines "
			     "connecting nearest elements");

    max_opt = G_define_option();
    max_opt->key = "dmax";
    max_opt->type = TYPE_DOUBLE;
    max_opt->required = NO;
    max_opt->answer = "-1";
    max_opt->description = _("Maximum distance or -1 for no limit");

    min_opt = G_define_option();
    min_opt->key = "dmin";
    min_opt->type = TYPE_DOUBLE;
    min_opt->required = NO;
    min_opt->answer = "-1";
    min_opt->description = _("Minimum distance or -1 for no limit");

    upload_opt = G_define_option();
    upload_opt->key = "upload";
    upload_opt->type = TYPE_STRING;
    upload_opt->required = YES;
    upload_opt->multiple = YES;
    upload_opt->options = "cat,dist,to_x,to_y,to_along,to_angle,to_attr";
    upload_opt->description =
	_("Values describing the relation between two nearest features");
    upload_opt->descriptions =
	_("cat;category of the nearest feature;"
	  "dist;minimum distance to nearest feature;"
	  "to_x;x coordinate of the nearest point on 'to' feature;"
	  "to_y;y coordinate of the nearest point on 'to' feature;"
	  "to_along;distance between points/centroids in 'from' map and the linear feature's "
	  "start point in 'to' map, along this linear feature;"
	  "to_angle;angle between the linear feature in 'to' map and the positive x axis, at "
	  "the location of point/centroid in 'from' map, counterclockwise, in radians, which "
	  "is between -PI and PI inclusive;"
	  "to_attr;attribute of nearest feature given by to_column option");
    /*  "from_x - x coordinate of the nearest point on 'from' feature;" */
    /*  "from_y - y coordinate of the nearest point on 'from' feature;" */
    /* "from_along - distance to the nearest point on 'from' feature along linear feature;" */

    column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    column_opt->required = YES;
    column_opt->multiple = YES;
    column_opt->description =
	_("Column name(s) where values specified by 'upload' option will be uploaded");
    column_opt->guisection = _("From_map");

    to_column_opt = G_define_standard_option(G_OPT_DB_COLUMN);
    to_column_opt->key = "to_column";
    to_column_opt->description =
	_("Column name of nearest feature (used with upload=to_attr)");
    to_column_opt->guisection = _("To");
    
    table_opt = G_define_standard_option(G_OPT_DB_TABLE);
    table_opt->gisprompt = "new_dbtable,dbtable,dbtable";
    table_opt->description =
	_("Name of table created for output when the distance to all flag is used");

    print_flag = G_define_flag();
    print_flag->key = 'p';
    print_flag->label =
	_("Print output to stdout, don't update attribute table");
    print_flag->description =
	_("First column is always category of 'from' feature called from_cat");

    all_flag = G_define_flag();
    all_flag->key = 'a';
    all_flag->label =
	_("Calculate distances to all features within the threshold");
    all_flag->description = _("The output is written to stdout but may be uploaded "
                              "to a new table created by this module. "
			      "From categories are may be multiple.");	/* huh? */

    /* GUI dependency */
    from_opt->guidependency = G_store(from_field_opt->key);
    sprintf(buf1, "%s,%s", to_field_opt->key, to_column_opt->key);
    to_opt->guidependency = G_store(buf1);
    to_field_opt->guidependency = G_store(to_column_opt->key);

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    from_type = Vect_option_to_types(from_type_opt);
    to_type = Vect_option_to_types(to_type_opt);

    from_field = atoi(from_field_opt->answer);

    max = atof(max_opt->answer);
    min = atof(min_opt->answer);

    if (all_flag->answer)
	all = 1;

    /* Read upload and column options */
    /* count */
    i = 0;
    while (upload_opt->answers[i])
	i++;
    if (strcmp(from_opt->answer, to_opt->answer) == 0 &&
	all && !table_opt->answer && i == 1)
	print_as_matrix = 1;

    /* alloc */
    Upload = (UPLOAD *) G_calloc(i + 1, sizeof(UPLOAD));
    /* read upload */
    i = 0;
    while (upload_opt->answers[i]) {
	if (strcmp(upload_opt->answers[i], "cat") == 0)
	    Upload[i].upload = CAT;
	else if (strcmp(upload_opt->answers[i], "from_x") == 0)
	    Upload[i].upload = FROM_X;
	else if (strcmp(upload_opt->answers[i], "from_y") == 0)
	    Upload[i].upload = FROM_Y;
	else if (strcmp(upload_opt->answers[i], "to_x") == 0)
	    Upload[i].upload = TO_X;
	else if (strcmp(upload_opt->answers[i], "to_y") == 0)
	    Upload[i].upload = TO_Y;
	else if (strcmp(upload_opt->answers[i], "from_along") == 0)
	    Upload[i].upload = FROM_ALONG;
	else if (strcmp(upload_opt->answers[i], "to_along") == 0)
	    Upload[i].upload = TO_ALONG;
	else if (strcmp(upload_opt->answers[i], "dist") == 0)
	    Upload[i].upload = DIST;
	else if (strcmp(upload_opt->answers[i], "to_angle") == 0)
	    Upload[i].upload = TO_ANGLE;
	else if (strcmp(upload_opt->answers[i], "to_attr") == 0) {
	    if (!(to_column_opt->answer)) {
		G_fatal_error(_("to_column option missing"));
	    }
	    Upload[i].upload = TO_ATTR;
	}

	i++;
    }
    Upload[i].upload = END;
    /* read columns */
    i = 0;
    while (column_opt->answers[i]) {
	if (Upload[i].upload == END) {
	    G_warning(_("Too many column names"));
	    break;
	}
	Upload[i].column = G_store(column_opt->answers[i]);
	i++;
    }
    if (Upload[i].upload != END)
	G_fatal_error(_("Not enough column names"));

    /* Open 'from' vector */
    Vect_set_open_level(2);
    Vect_open_old(&From, from_opt->answer, G_mapset());

    /* Open 'to' vector */
    Vect_set_open_level(2);
    Vect_open_old2(&To, to_opt->answer, "", to_field_opt->answer);

    to_field = Vect_get_field_number(&To, to_field_opt->answer);

    /* Open output vector */
    if (out_opt->answer) {
	Vect_open_new(&Out, out_opt->answer, WITHOUT_Z);
	Vect_hist_command(&Out);
	Outp = &Out;
    }
    else {
	Outp = NULL;
    }

    /* TODO: add maxdist = -1 to Vect_select_ !!! */
    /* Calc maxdist */
    n_max_steps = 1;
    if (max != 0) {
	struct bound_box fbox, tbox;
	double dx, dy, dz, tmp_max;
	int n_features = 0;

	Vect_get_map_box(&From, &fbox);
	Vect_get_map_box(&To, &tbox);

	Vect_box_extend(&fbox, &tbox);

	dx = fbox.E - fbox.W;
	dy = fbox.N - fbox.S;
	if (Vect_is_3d(&From))
	    dz = fbox.T - fbox.B;
	else
	    dz = 0.0;

	tmp_max = sqrt(dx * dx + dy * dy + dz * dz);
	if (max < 0)
	    max = tmp_max;

	/* how to determine a reasonable number of steps to increase the search box? */
	/* with max > 0 but max <<< tmp_max, 2 steps are sufficient, first 0 then max
	 * a reasonable number of steps also depends on the number of features in To
	 * e.g. only one area in To, no need to step */
	nto = Vect_get_num_lines(&To);
	for (tline = 1; tline <= nto; tline++) {
	    /* TODO: Vect_get_line_type() */
	    n_features += ((to_type & To.plus.Line[tline]->type) != 0);
	}
	if (to_type & GV_AREA) {
	    if (Vect_get_num_areas(&To) > n_features)
		n_features = Vect_get_num_areas(&To);
	}
	if (n_features == 0)
	    G_fatal_error(_("No features of selected type in To vector <%s>"),
			    to_opt->answer);
	n_max_steps = sqrt(n_features) * max / tmp_max;
	/* max 9 steps from testing */
	if (n_max_steps > 9)
	    n_max_steps = 9;
	if (n_max_steps < 2)
	    n_max_steps = 2;
	if (n_max_steps > n_features)
	    n_max_steps = n_features;

	G_debug(2, "max = %f", max);
	G_debug(2, "maximum reasonable search distance = %f", tmp_max);
	G_debug(2, "n_features = %d", n_features);
	G_debug(2, "n_max_steps = %d", n_max_steps);
    }

    if (min > max)
	G_fatal_error("dmin can not be larger than dmax");

    if (n_max_steps > 1) {
	/* set up steps to increase search box */
	max_step = G_malloc(n_max_steps * sizeof(double));
	/* first step always 0 */
	max_step[0] = 0;

	for (curr_step = 1; curr_step < n_max_steps - 1; curr_step++) {
	    /* for 9 steps, this would be max / [128, 64, 32, 16, 8, 4, 2] */
	    max_step[curr_step] = max / (2 << (n_max_steps - 1 - curr_step));
	}
	/* last step always max */
	max_step[n_max_steps - 1] = max;
    }
    else {
	max_step = G_malloc(sizeof(double));
	max_step[0] = max;
    }

    /* Open database driver */
    db_init_string(&stmt);
    db_init_string(&dbstr);
    driver = NULL;
    if (!print_flag->answer) {

	if (!all) {
	    Fi = Vect_get_field(&From, from_field);
	    if (Fi == NULL)
		G_fatal_error(_("Database connection not defined for layer %d"),
			      from_field);

	    driver = db_start_driver_open_database(Fi->driver, Fi->database);
	    if (driver == NULL)
		G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			      Fi->database, Fi->driver);

	    /* check if column exists */
	    i = 0;
	    while (column_opt->answers[i]) {
		db_get_column(driver, Fi->table, column_opt->answers[i],
			      &column);
		if (column) {
		    db_free_column(column);
		    column = NULL;
		}
		else {
		    G_fatal_error(_("Column <%s> not found in table <%s>"),
				  column_opt->answers[i], Fi->table);
		}
		i++;
	    }
	}
	else {
	    driver = db_start_driver_open_database(NULL, NULL);
	    if (driver == NULL)
		G_fatal_error(_("Unable to open default database"));
	}
    }

    to_driver = NULL;
    if (to_column_opt->answer) {
	toFi = Vect_get_field(&To, to_field);
	if (toFi == NULL)
	    G_fatal_error(_("Database connection not defined for layer %d"),
			  to_field);

	to_driver =
	    db_start_driver_open_database(toFi->driver, toFi->database);
	if (to_driver == NULL)
	    G_fatal_error(_("Unable to open database <%s> by driver <%s>"),
			  toFi->database, toFi->driver);

	/* check if to_column exists */
	db_get_column(to_driver, toFi->table, to_column_opt->answer, &column);
	if (column) {
	    db_free_column(column);
	    column = NULL;
	}
	else {
	    G_fatal_error(_("Column <%s> not found in table <%s>"),
			  to_column_opt->answer, toFi->table);
	}

	/* Check column types */
	if (!print_flag->answer && !all) {
	    char *fcname = NULL;
	    int fctype, tctype;

	    i = 0;
	    while (column_opt->answers[i]) {
		if (Upload[i].upload == TO_ATTR) {
		    fcname = column_opt->answers[i];
		    break;
		}
		i++;
	    }

	    if (fcname) {
		fctype = db_column_Ctype(driver, Fi->table, fcname);
		tctype =
		    db_column_Ctype(to_driver, toFi->table,
				    to_column_opt->answer);

		if (((tctype == DB_C_TYPE_STRING ||
		      tctype == DB_C_TYPE_DATETIME)
		     && (fctype == DB_C_TYPE_INT ||
			 fctype == DB_C_TYPE_DOUBLE)) ||
		    ((tctype == DB_C_TYPE_INT || tctype == DB_C_TYPE_DOUBLE)
		     && (fctype == DB_C_TYPE_STRING ||
			 fctype == DB_C_TYPE_DATETIME))
		    ) {
		    G_fatal_error(_("Incompatible column types"));
		}
	    }
	}
    }

    FPoints = Vect_new_line_struct();
    TPoints = Vect_new_line_struct();
    FCats = Vect_new_cats_struct();
    TCats = Vect_new_cats_struct();
    List = Vect_new_boxlist(1);

    /* Allocate space ( may be more than needed (duplicate cats and elements without cats) ) */
    nfrom = Vect_get_num_lines(&From);
    nto = Vect_get_num_lines(&To);
    if (all) {
	/* Attention with space for all, it can easily run out of memory */
	anear = 2 * nfrom;
	Near = (NEAR *) G_calloc(anear, sizeof(NEAR));
    }
    else {
	Near = (NEAR *) G_calloc(nfrom, sizeof(NEAR));
    }

    /* Read all cats from 'from' */
    if (!all) {
	nfcats = 0;
	for (i = 1; i <= nfrom; i++) {
	    ftype = Vect_read_line(&From, NULL, FCats, i);

	    /* This keeps also categories of areas for future (if area s in from_type) */
	    if (!(ftype & from_type) &&
		(ftype != GV_CENTROID || !(from_type & GV_AREA)))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0)
		continue;
	    Near[nfcats].from_cat = fcat;
	    nfcats++;
	}
	G_debug(1, "%d cats loaded from vector (including duplicates)",
		nfcats);
	/* Sort by cats and remove duplicates */
	qsort((void *)Near, nfcats, sizeof(NEAR), cmp_near);

	/* remove duplicates */
	for (i = 1; i < nfcats; i++) {
	    if (Near[i].from_cat == Near[i - 1].from_cat) {
		for (j = i; j < nfcats - 1; j++) {
		    Near[j].from_cat = Near[j + 1].from_cat;
		}
		nfcats--;
	    }
	}

	G_debug(1, "%d cats loaded from vector (unique)", nfcats);
    }

    /* Go through all lines in 'from' and find nearest in 'to' for each */
    /* Note: as from_type is restricted to GV_POINTS (for now) everything is simple */

    count = 0;			/* count of distances in 'all' mode */
    /* Find nearest lines */
    if (to_type & (GV_POINTS | GV_LINES)) {
	struct line_pnts *LLPoints;

	if (G_projection() == PROJECTION_LL) {
	    LLPoints = Vect_new_line_struct();
	}
	else {
	    LLPoints = NULL;
	}
	G_message(_("Finding nearest feature..."));
	for (fline = 1; fline <= nfrom; fline++) {
	    int tmp_tcat;
	    double tmp_tangle, tangle;
	    double tmp_min = (min < 0 ? 0 : min);
	    double box_edge = 0;
	    int done = 0;

	    curr_step = 0;

	    G_debug(3, "fline = %d", fline);
	    G_percent(fline, nfrom, 2);
	    ftype = Vect_read_line(&From, FPoints, FCats, fline);
	    if (!(ftype & from_type))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0 && !all)
		continue;

	    while (!done) {
		done = 1;

		if (!all) {
		    /* enlarge search box until we get a hit */
		    /* the objective is to enlarge the search box
		     * in the first iterations just a little bit
		     * to keep the number of hits low */
		    Vect_reset_boxlist(List);
		    while (curr_step < n_max_steps) {
			box_edge = max_step[curr_step];

			if (box_edge < tmp_min)
			    continue;
			
			box.E = FPoints->x[0] + box_edge;
			box.W = FPoints->x[0] - box_edge;
			box.N = FPoints->y[0] + box_edge;
			box.S = FPoints->y[0] - box_edge;
			box.T = PORT_DOUBLE_MAX;
			box.B = -PORT_DOUBLE_MAX;

			Vect_select_lines_by_box(&To, &box, to_type, List);

			curr_step++;
			if (List->n_values > 0)
			    break;
		    }
		}
		else {
		    box.E = FPoints->x[0] + max;
		    box.W = FPoints->x[0] - max;
		    box.N = FPoints->y[0] + max;
		    box.S = FPoints->y[0] - max;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;

		    Vect_select_lines_by_box(&To, &box, to_type, List);
		}

		G_debug(3, "  %d lines in box", List->n_values);

		tline = 0;
		dist = PORT_DOUBLE_MAX;
		for (i = 0; i < List->n_values; i++) {
		    tmp_tcat = -1;
		    Vect_read_line(&To, TPoints, TCats, List->id[i]);

		    tseg =
			Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0],
					   FPoints->z[0], (Vect_is_3d(&From) &&
							   Vect_is_3d(&To)) ?
					   WITH_Z : WITHOUT_Z, &tmp_tx, &tmp_ty,
					   &tmp_tz, &tmp_dist, NULL, &tmp_talong);

		    Vect_point_on_line(TPoints, tmp_talong, NULL, NULL, NULL,
				       &tmp_tangle, NULL);

		    if (tmp_dist > max || tmp_dist < min)
			continue;	/* not in threshold */

		    /* TODO: more cats of the same field */
		    Vect_cat_get(TCats, to_field, &tmp_tcat);
		    if (G_projection() == PROJECTION_LL) {
			/* calculate distances in meters not degrees (only 2D) */
			Vect_reset_line(LLPoints);
			Vect_append_point(LLPoints, FPoints->x[0], FPoints->y[0],
					  FPoints->z[0]);
			Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz);
			tmp_dist = Vect_line_geodesic_length(LLPoints);
			Vect_reset_line(LLPoints);
			for (k = 0; k < tseg; k++)
			    Vect_append_point(LLPoints, TPoints->x[k],
					      TPoints->y[k], TPoints->z[k]);
			Vect_append_point(LLPoints, tmp_tx, tmp_ty, tmp_tz);
			tmp_talong = Vect_line_geodesic_length(LLPoints);
		    }

		    G_debug(4, "  tmp_dist = %f tmp_tcat = %d", tmp_dist,
			    tmp_tcat);

		    if (all) {
			if (anear <= count) {
			    anear += 10 + nfrom / 10;
			    Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR));
			}
			near = &(Near[count]);

			/* store info about relation */
			near->from_cat = fcat;
			near->to_cat = tmp_tcat;	/* -1 is OK */
			near->dist = tmp_dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->from_z = FPoints->z[0];
			near->to_x = tmp_tx;
			near->to_y = tmp_ty;
			near->to_z = tmp_tz;
			near->to_along = tmp_talong;	/* 0 for points */
			near->to_angle = tmp_tangle;
			near->count++;
			count++;
		    }
		    else {
			if (tline == 0 || (tmp_dist < dist)) {
			    tline = List->id[i];
			    tcat = tmp_tcat;
			    dist = tmp_dist;
			    tx = tmp_tx;
			    ty = tmp_ty;
			    tz = tmp_tz;
			    talong = tmp_talong;
			    tangle = tmp_tangle;
			}
		    }
		}

		G_debug(4, "  dist = %f", dist);

		if (curr_step < n_max_steps) {
		    /* enlarging the search box is possible */
		    if (tline > 0 && dist > box_edge) {
			/* line found but distance > search edge:
			 * line bbox overlaps with search box, line itself is outside search box */
			done = 0;
		    }
		    else if (tline == 0) {
			/* no line within max dist, but search box can still be enlarged */
			done = 0;
		    }
		}
		if (done && !all && tline > 0) {
		    /* find near by cat */
		    near =
			(NEAR *) bsearch((void *)&fcat, Near, nfcats,
					 sizeof(NEAR), cmp_near);

		    G_debug(4, "  near.from_cat = %d near.count = %d",
			    near->from_cat, near->count);
		    /* store info about relation */
		    if (near->count == 0 || near->dist > dist) {
			near->to_cat = tcat;	/* -1 is OK */
			near->dist = dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->from_z = FPoints->z[0];
			near->to_x = tx;
			near->to_y = ty;
			near->to_z = tz;
			near->to_along = talong;	/* 0 for points */
			near->to_angle = tangle;
		    }
		    near->count++;
		}
	    } /* done */
	} /* next feature */
	if (LLPoints) {
	    Vect_destroy_line_struct(LLPoints);
	}
    }

    /* Find nearest areas */
    if (to_type & GV_AREA) {
	
	G_message(_("Finding nearest areas..."));
	for (fline = 1; fline <= nfrom; fline++) {
	    double tmp_min = (min < 0 ? 0 : min);
	    double box_edge = 0;
	    int done = 0;
	    
	    curr_step = 0;

	    G_debug(3, "fline = %d", fline);
	    G_percent(fline, nfrom, 2);
	    ftype = Vect_read_line(&From, FPoints, FCats, fline);
	    if (!(ftype & from_type))
		continue;

	    Vect_cat_get(FCats, from_field, &fcat);
	    if (fcat < 0 && !all)
		continue;

	    while (!done) {
		done = 1;

		if (!all) {
		    /* enlarge search box until we get a hit */
		    /* the objective is to enlarge the search box
		     * in the first iterations just a little bit
		     * to keep the number of hits low */
		    Vect_reset_boxlist(List);
		    while (curr_step < n_max_steps) {
			box_edge = max_step[curr_step];

			if (box_edge < tmp_min)
			    continue;
			
			box.E = FPoints->x[0] + box_edge;
			box.W = FPoints->x[0] - box_edge;
			box.N = FPoints->y[0] + box_edge;
			box.S = FPoints->y[0] - box_edge;
			box.T = PORT_DOUBLE_MAX;
			box.B = -PORT_DOUBLE_MAX;

			Vect_select_areas_by_box(&To, &box, List);

			curr_step++;
			if (List->n_values > 0)
			    break;
		    }
		}
		else {
		    box.E = FPoints->x[0] + max;
		    box.W = FPoints->x[0] - max;
		    box.N = FPoints->y[0] + max;
		    box.S = FPoints->y[0] - max;
		    box.T = PORT_DOUBLE_MAX;
		    box.B = -PORT_DOUBLE_MAX;

		    Vect_select_areas_by_box(&To, &box, List);
		}

		G_debug(4, "%d areas selected by box", List->n_values);

		/* For each area in box check the distance */
		tarea = 0;
		dist = PORT_DOUBLE_MAX;
		for (i = 0; i < List->n_values; i++) {
		    int tmp_tcat;

		    area = List->id[i];
		    G_debug(4, "%d: area %d", i, area);
		    Vect_get_area_points(&To, area, TPoints);

		    /* Find the distance to this area */
		    if (Vect_point_in_area(FPoints->x[0], FPoints->y[0], &To, area, List->box[i])) {	/* in area */
			tmp_dist = 0;
			tmp_tx = FPoints->x[0];
			tmp_ty = FPoints->y[0];
		    }
		    else if (Vect_point_in_poly(FPoints->x[0], FPoints->y[0], TPoints) > 0) {	/* in isle */
			nisles = Vect_get_area_num_isles(&To, area);
			for (j = 0; j < nisles; j++) {
			    double tmp2_dist, tmp2_tx, tmp2_ty;

			    isle = Vect_get_area_isle(&To, area, j);
			    Vect_get_isle_points(&To, isle, TPoints);
			    Vect_line_distance(TPoints, FPoints->x[0],
					       FPoints->y[0], FPoints->z[0],
					       WITHOUT_Z, &tmp2_tx, &tmp2_ty,
					       NULL, &tmp2_dist, NULL, NULL);

			    if (j == 0 || tmp2_dist < tmp_dist) {
				tmp_dist = tmp2_dist;
				tmp_tx = tmp2_tx;
				tmp_ty = tmp2_ty;
			    }
			}
		    }
		    else {		/* outside area */
			Vect_line_distance(TPoints, FPoints->x[0], FPoints->y[0],
					   FPoints->z[0], WITHOUT_Z, &tmp_tx,
					   &tmp_ty, NULL, &tmp_dist, NULL, NULL);

		    }
		    if (tmp_dist > max || tmp_dist < min)
			continue;	/* not in threshold */
		    Vect_get_area_cats(&To, area, TCats);
		    tmp_tcat = -1;
		    /* TODO: all cats of given field ? */
		    for (j = 0; j < TCats->n_cats; j++) {
			if (TCats->field[j] == to_field) {
			    if (tmp_tcat >= 0)
				G_warning(_("More cats found in to_layer (area=%d)"),
					  area);
			    tmp_tcat = TCats->cat[j];
			}
		    }

		    G_debug(4, "  tmp_dist = %f tmp_tcat = %d", tmp_dist,
			    tmp_tcat);

		    if (all) {
			if (anear <= count) {
			    anear += 10 + nfrom / 10;
			    Near = (NEAR *) G_realloc(Near, anear * sizeof(NEAR));
			}
			near = &(Near[count]);

			/* store info about relation */
			near->from_cat = fcat;
			near->to_cat = tmp_tcat;	/* -1 is OK */
			near->dist = tmp_dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->to_x = tmp_tx;
			near->to_y = tmp_ty;
			near->to_along = 0;	/* nonsense for areas */
			near->to_angle = 0;	/* not supported for areas */
			near->count++;
			count++;
		    }
		    else if (tarea == 0 || tmp_dist < dist) {
			tarea = area;
			tcat = tmp_tcat;
			dist = tmp_dist;
			tx = tmp_tx;
			ty = tmp_ty;
		    }
		}

		if (curr_step < n_max_steps) {
		    /* enlarging the search box is possible */
		    if (tarea > 0 && dist > box_edge) {
			/* area found but distance > search edge:
			 * area bbox overlaps with search box, area itself is outside search box */
			done = 0;
		    }
		    else if (tarea == 0) {
			/* no area within max dist, but search box can still be enlarged */
			done = 0;
		    }
		}
		if (done && !all && tarea > 0) {
		    /* find near by cat */
		    near =
			(NEAR *) bsearch((void *)&fcat, Near, nfcats,
					 sizeof(NEAR), cmp_near);

		    G_debug(4, "near.from_cat = %d near.count = %d dist = %f",
			    near->from_cat, near->count, near->dist);

		    /* store info about relation */
		    if (near->count == 0 || near->dist > dist) {
			near->to_cat = tcat;	/* -1 is OK */
			near->dist = dist;
			near->from_x = FPoints->x[0];
			near->from_y = FPoints->y[0];
			near->to_x = tx;
			near->to_y = ty;
			near->to_along = 0;	/* nonsense for areas */
			near->to_angle = 0;	/* not supported for areas */
		    }
		    near->count++;
		}
	    } /* done */
	} /* next feature */
    }

    G_debug(3, "count = %d", count);

    /* Update database / print to stdout / create output map */
    if (print_flag->answer) {	/* print header */
	fprintf(stdout, "from_cat");
	i = 0;
	while (Upload[i].upload != END) {
	    fprintf(stdout, "|%s", Upload[i].column);
	    i++;
	}
	fprintf(stdout, "\n");
    }
    else if (all && table_opt->answer) {	/* create new table */
	db_set_string(&stmt, "create table ");
	db_append_string(&stmt, table_opt->answer);
	db_append_string(&stmt, " (from_cat integer");

	j = 0;
	while (Upload[j].upload != END) {
	    db_append_string(&stmt, ", ");

	    switch (Upload[j].upload) {
	    case CAT:
		sprintf(buf2, "%s integer", Upload[j].column);
		break;
	    case DIST:
	    case FROM_X:
	    case FROM_Y:
	    case TO_X:
	    case TO_Y:
	    case FROM_ALONG:
	    case TO_ALONG:
	    case TO_ANGLE:
		sprintf(buf2, "%s double precision", Upload[j].column);
	    }
	    db_append_string(&stmt, buf2);
	    j++;
	}
	db_append_string(&stmt, " )");
	G_debug(3, "SQL: %s", db_get_string(&stmt));

	if (db_execute_immediate(driver, &stmt) != DB_OK)
	    G_fatal_error(_("Unable to create table: '%s'"),
			  db_get_string(&stmt));

	if (db_grant_on_table(driver, table_opt->answer, DB_PRIV_SELECT,
			      DB_GROUP | DB_PUBLIC) != DB_OK)
	    G_fatal_error(_("Unable to grant privileges on table <%s>"),
			  table_opt->answer);

    }
    else if (!all) {		/* read existing cats from table */
	ncatexist =
	    db_select_int(driver, Fi->table, Fi->key, NULL, &catexist);
	G_debug(1, "%d cats selected from the table", ncatexist);
    }
    update_ok = update_err = update_exist = update_notexist = update_dupl =
	update_notfound = 0;

    if (!all) {
	count = nfcats;
    }
    else if (print_as_matrix) {
	qsort((void *)Near, count, sizeof(NEAR), cmp_near_to);
    }

    if (driver)
	db_begin_transaction(driver);

    /* select 'to' attributes */
    if (to_column_opt->answer) {
	int nrec;

	db_CatValArray_init(&cvarr);
	nrec = db_select_CatValArray(to_driver, toFi->table, toFi->key,
				     to_column_opt->answer, NULL, &cvarr);
	G_debug(3, "selected values = %d", nrec);

	if (cvarr.ctype == DB_C_TYPE_DATETIME) {
	    G_warning(_("DATETIME type not yet supported, no attributes will be uploaded"));
	}
	db_close_database_shutdown_driver(to_driver);
    }

    if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */
	G_message("Update database...");

    for (i = 0; i < count; i++) {
	dbCatVal *catval = 0;

	if (!(print_flag->answer || (all && !table_opt->answer))) /* no printing */
	    G_percent(i, count, 1);

	/* Write line connecting nearest points */
	if (Outp != NULL) {
	    Vect_reset_line(FPoints);
	    Vect_reset_cats(FCats);

	    Vect_append_point(FPoints, Near[i].from_x, Near[i].from_y, 0);

	    if (Near[i].dist == 0) {
		Vect_write_line(Outp, GV_POINT, FPoints, FCats);
	    }
	    else {
		Vect_append_point(FPoints, Near[i].to_x, Near[i].to_y, 0);
		Vect_write_line(Outp, GV_LINE, FPoints, FCats);
	    }

	}

	if (Near[i].count > 1)
	    update_dupl++;
	if (Near[i].count == 0)
	    update_notfound++;

	if (to_column_opt->answer && Near[i].count > 0) {
	    db_CatValArray_get_value(&cvarr, Near[i].to_cat, &catval);
	}

	if (print_flag->answer || (all && !table_opt->answer)) {	/* print only */
	    /*
	       input and output is the same &&
	       calculate distances &&
	       only one upload option given ->
	       print as a matrix
	     */
	    if (print_as_matrix) {
		if (i == 0) {
		    for (j = 0; j < nfrom; j++) {
			if (j == 0)
			    fprintf(stdout, " ");
			fprintf(stdout, "|%d", Near[j].to_cat);
		    }
		    fprintf(stdout, "\n");
		}
		if (i % nfrom == 0) {
		    fprintf(stdout, "%d", Near[i].from_cat);
		    for (j = 0; j < nfrom; j++) {
			print_upload(Near, Upload, i + j, &cvarr, catval);
		    }
		    fprintf(stdout, "\n");
		}
	    }
	    else {
		fprintf(stdout, "%d", Near[i].from_cat);
		print_upload(Near, Upload, i, &cvarr, catval);
		fprintf(stdout, "\n");
	    }
	}
	else if (all) {		/* insert new record */
	    sprintf(buf1, "insert into %s values ( %d ", table_opt->answer,
		    Near[i].from_cat);
	    db_set_string(&stmt, buf1);

	    j = 0;
	    while (Upload[j].upload != END) {
		db_append_string(&stmt, ",");

		switch (Upload[j].upload) {
		case CAT:
		    sprintf(buf2, " %d", Near[i].to_cat);
		    break;
		case DIST:
		    sprintf(buf2, " %f", Near[i].dist);
		    break;
		case FROM_X:
		    sprintf(buf2, " %f", Near[i].from_x);
		    break;
		case FROM_Y:
		    sprintf(buf2, " %f", Near[i].from_y);
		    break;
		case TO_X:
		    sprintf(buf2, " %f", Near[i].to_x);
		    break;
		case TO_Y:
		    sprintf(buf2, " %f", Near[i].to_y);
		    break;
		case FROM_ALONG:
		    sprintf(buf2, " %f", Near[i].from_along);
		    break;
		case TO_ALONG:
		    sprintf(buf2, " %f", Near[i].to_along);
		    break;
		case TO_ANGLE:
		    sprintf(buf2, " %f", Near[i].to_angle);
		    break;
		case TO_ATTR:
		    if (catval) {
			switch (cvarr.ctype) {
			case DB_C_TYPE_INT:
			    sprintf(buf2, " %d", catval->val.i);
			    break;

			case DB_C_TYPE_DOUBLE:
			    sprintf(buf2, " %.15e", catval->val.d);
			    break;

			case DB_C_TYPE_STRING:
			    db_set_string(&dbstr,
					  db_get_string(catval->val.s));
			    db_double_quote_string(&dbstr);
			    sprintf(buf2, " '%s'", db_get_string(&dbstr));
			    break;

			case DB_C_TYPE_DATETIME:
			    /* TODO: formating datetime */
			    sprintf(buf2, " null");
			    break;
			}
		    }
		    else {
			sprintf(buf2, " null");
		    }
		    break;
		}
		db_append_string(&stmt, buf2);
		j++;
	    }
	    db_append_string(&stmt, " )");
	    G_debug(3, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(driver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }
	}
	else {			/* update table */
	    /* check if exists in table */
	    cex =
		(int *)bsearch((void *)&(Near[i].from_cat), catexist,
			       ncatexist, sizeof(int), cmp_exist);
	    if (cex == NULL) {	/* cat does not exist in DB */
		update_notexist++;
		continue;
	    }
	    update_exist++;

	    sprintf(buf1, "update %s set", Fi->table);
	    db_set_string(&stmt, buf1);

	    j = 0;
	    while (Upload[j].upload != END) {
		if (j > 0)
		    db_append_string(&stmt, ",");

		sprintf(buf2, " %s =", Upload[j].column);
		db_append_string(&stmt, buf2);

		if (Near[i].count == 0) {	/* no nearest found */
		    db_append_string(&stmt, " null");
		}
		else {
		    switch (Upload[j].upload) {
		    case CAT:
			if (Near[i].to_cat > 0)
			    sprintf(buf2, " %d", Near[i].to_cat);
			else
			    sprintf(buf2, " null");
			break;
		    case DIST:
			sprintf(buf2, " %f", Near[i].dist);
			break;
		    case FROM_X:
			sprintf(buf2, " %f", Near[i].from_x);
			break;
		    case FROM_Y:
			sprintf(buf2, " %f", Near[i].from_y);
			break;
		    case TO_X:
			sprintf(buf2, " %f", Near[i].to_x);
			break;
		    case TO_Y:
			sprintf(buf2, " %f", Near[i].to_y);
			break;
		    case FROM_ALONG:
			sprintf(buf2, " %f", Near[i].from_along);
			break;
		    case TO_ALONG:
			sprintf(buf2, " %f", Near[i].to_along);
			break;
		    case TO_ANGLE:
			sprintf(buf2, " %f", Near[i].to_angle);
			break;
		    case TO_ATTR:
			if (catval) {
			    switch (cvarr.ctype) {
			    case DB_C_TYPE_INT:
				sprintf(buf2, " %d", catval->val.i);
				break;

			    case DB_C_TYPE_DOUBLE:
				sprintf(buf2, " %.15e", catval->val.d);
				break;

			    case DB_C_TYPE_STRING:
				db_set_string(&dbstr,
					      db_get_string(catval->val.s));
				db_double_quote_string(&dbstr);
				sprintf(buf2, " '%s'", db_get_string(&dbstr));
				break;

			    case DB_C_TYPE_DATETIME:
				/* TODO: formating datetime */
				sprintf(buf2, " null");
				break;
			    }
			}
			else {
			    sprintf(buf2, " null");
			}
			break;
		    }
		    db_append_string(&stmt, buf2);
		}
		j++;
	    }
	    sprintf(buf2, " where %s = %d", Fi->key, Near[i].from_cat);
	    db_append_string(&stmt, buf2);
	    G_debug(2, "SQL: %s", db_get_string(&stmt));
	    if (db_execute_immediate(driver, &stmt) == DB_OK) {
		update_ok++;
	    }
	    else {
		update_err++;
	    }
	}
    }
    G_percent(count, count, 1);

    if (driver)
	db_commit_transaction(driver);

    /* print stats */
    if (update_dupl > 0)
	G_message(_("%d categories with more than 1 feature in vector map <%s>"),
		  update_dupl, from_opt->answer);
    if (update_notfound > 0)
	G_message(_("%d categories - no nearest feature found"),
		  update_notfound);

    if (!print_flag->answer) {
	db_close_database_shutdown_driver(driver);
	db_free_string(&stmt);

	/* print stats */
	if (all && table_opt->answer) {
	    G_message(_("%d distances calculated"), count);
	    G_message(_("%d records inserted"), update_ok);
	    if (update_err > 0)
		G_message(_("%d insert errors"), update_err);
	}
	else if (!all) {
	    if (nfcats > 0)
		G_message(_("%d categories read from the map"), nfcats);
	    if (ncatexist > 0)
		G_message(_("%d categories exist in the table"), ncatexist);
	    if (update_exist > 0)
		G_message(_("%d categories read from the map exist in the table"),
			  update_exist);
	    if (update_notexist > 0)
		G_message(_("%d categories read from the map don't exist in the table"),
			  update_notexist);
	    G_message(_("%d records updated"), update_ok);
	    if (update_err > 0)
		G_message(_("%d update errors"), update_err);

	    G_free(catexist);
	}

	Vect_set_db_updated(&From);
    }

    Vect_close(&From);
    if (Outp != NULL) {
	Vect_build(Outp);
	Vect_close(Outp);
    }

    G_done_msg(" ");

    exit(EXIT_SUCCESS);
}