/*! \file lib/vector/Vlib/area_pg.c \brief Vector library - area-related functions (PostGIS Topology) Higher level functions for reading/writing/manipulating vectors. (C) 2013 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author Martin Landa */ #include #ifdef HAVE_POSTGRES #include "pg_local_proto.h" static PGresult *build_stmt(const struct Plus_head *, const struct Format_info_pg *, const plus_t *, int); /*! \brief Get area boundary points (PostGIS Topology) Used by Vect_build_line_area() and Vect_get_area_points(). \param Map pointer to Map_info struct \param lines array of boundary lines \param n_lines number of lines in array \param[out] APoints pointer to output line_pnts struct \return number of points \return -1 on error */ int Vect__get_area_points_pg(const struct Map_info *Map, const plus_t *lines, int n_lines, struct line_pnts *APoints) { int i, direction; struct Format_info_pg *pg_info; PGresult *res; pg_info = (struct Format_info_pg *)&(Map->fInfo.pg); Vect_reset_line(APoints); res = build_stmt(&(Map->plus), pg_info, lines, n_lines); if (!res) return -1; for (i = 0; i < n_lines; i++) { Vect__cache_feature_pg(PQgetvalue(res, i, 0), FALSE, FALSE, &(pg_info->cache), NULL); /* do caching in readable way */ direction = lines[i] > 0 ? GV_FORWARD : GV_BACKWARD; Vect_append_points(APoints, pg_info->cache.lines[0], direction); APoints->n_points--; /* skip last point, avoids duplicates */ } APoints->n_points++; /* close polygon */ PQclear(res); return APoints->n_points; } PGresult *build_stmt(const struct Plus_head *plus, const struct Format_info_pg *pg_info, const plus_t *lines, int n_lines) { int i, line; size_t stmt_id_size; char *stmt, *stmt_id, buf_id[128]; struct P_line *BLine; PGresult *res; stmt = NULL; stmt_id_size = DB_SQL_MAX; stmt_id = (char *) G_malloc(stmt_id_size); stmt_id[0] = '\0'; for (i = 0; i < n_lines; i++) { if (strlen(stmt_id) + 100 > stmt_id_size) { stmt_id_size = strlen(stmt_id) + DB_SQL_MAX; stmt_id = (char *) G_realloc(stmt_id, stmt_id_size); } line = abs(lines[i]); BLine = plus->Line[line]; if (i > 0) strcat(stmt_id, ","); sprintf(buf_id, "%d", (int) BLine->offset); strcat(stmt_id, buf_id); } /* Not really working - why? G_asprintf(&stmt, "SELECT geom FROM \"%s\".edge_data WHERE edge_id IN (%s) " "ORDER BY POSITION(edge_id::text in '%s')", pg_info->toposchema_name, stmt_id, stmt_id); */ G_asprintf(&stmt, "SELECT geom FROM \"%s\".edge_data AS t " "JOIN (SELECT id, row_number() over() AS id_sorter FROM " "(SELECT UNNEST(ARRAY[%s]) AS id) AS y) x ON " "t.edge_id in (%s) AND x.id = t.edge_id " "ORDER BY x.id_sorter", pg_info->toposchema_name, stmt_id, stmt_id); G_free(stmt_id); G_debug(2, "SQL: %s", stmt); res = PQexec(pg_info->conn, stmt); G_free(stmt); if (!res || PQresultStatus(res) != PGRES_TUPLES_OK || PQntuples(res) != n_lines) { if (res) PQclear(res); return NULL; } return res; } #endif