33 #include "local_proto.h"
36 #include "pg_local_proto.h"
40 static unsigned char *wkb_data;
41 static unsigned int wkb_data_length;
46 static unsigned char *hex_to_wkb(
const char *,
int *);
47 static int point_from_wkb(
const unsigned char *,
int,
int,
int,
49 static int linestring_from_wkb(
const unsigned char *,
int,
int,
int,
51 static int polygon_from_wkb(
const unsigned char *,
int,
int,
int,
53 static int geometry_collection_from_wkb(
const unsigned char *,
int,
int,
int,
56 static int error_corrupted_data(
const char *);
57 static void add_fpart(
struct feat_parts *,
SF_FeatureType,
int,
int);
64 #define NOPG_UNUSED UNUSED
93 G_debug(3,
"V1_read_next_line_pg()");
96 return read_next_line_pg(Map, line_p, line_c,
FALSE);
130 G_debug(3,
"V2_read_next_line_pg()");
132 pg_info = &(Map->fInfo.pg);
134 if (Map->constraint.region_flag)
139 line = Map->next_line;
141 if (Map->next_line > Map->plus.n_lines)
144 Line = Map->plus.Line[line];
150 if (Map->constraint.type_flag) {
152 if (!(Line->
type & Map->constraint.type)) {
159 G_debug(4,
"Determine centroid for simple features");
161 if (line_p !=
NULL) {
174 for (i = 0; i <
list.n_values; i++) {
175 if (
list.id[i] == line) {
184 list.box[found].N, 0.0);
187 if (line_c !=
NULL) {
197 ret = read_next_line_pg(Map, line_p, line_c,
TRUE);
198 if (ret != Line->
type) {
199 G_warning(
_(
"Unexpected feature type (%d) - should be (%d)"),
205 if (Map->constraint.region_flag) {
221 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
256 pg_info = &(Map->fInfo.pg);
258 G_debug(3,
"V1_read_line_pg(): offset = %lu offset_num = %lu", (
long)
offset,
276 G_debug(3,
"read (%s) feature (fid = %ld) to cache",
281 G_warning(
_(
"Feature %ld without geometry skipped"), fid);
297 G_debug(3,
"read feature part: %d -> type = %d", ipart, type);
307 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
338 pg_info = &(Map->fInfo.pg);
340 if (line < 1 || line > Map->plus.n_lines) {
341 G_warning(
_(
"Attempt to access feature with invalid id (%d)"), line);
345 Line = Map->plus.Line[line];
347 G_warning(
_(
"Attempt to access dead feature %d"), line);
351 G_debug(4,
"V2_read_line_pg() line = %d type = %d offset = %" PRId64, line,
354 if (!line_p && !line_c)
361 return get_centroid(Map, line, line_p, line_c);
372 cache_idx = line - 1;
376 "Number of features in cache: %d"),
379 G_warning(
_(
"Feature %d: unexpected type (%d) - should be %d"),
389 G_warning(
_(
"Feature %d without geometry skipped"), line);
411 if (!PQgetisnull(pg_info->
res, 0, col_idx))
413 atoi(PQgetvalue(pg_info->
res, 0, col_idx));
427 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
448 struct line_cats *line_c,
int ignore_constraints)
480 G_warning(
_(
"Feature %ld without geometry skipped"),
485 if ((
int)sf_type < 0) {
492 G_warning(
_(
"Feature without geometry. Skipped."));
508 }
while (iline ==
NULL);
510 G_debug(4,
"read next cached line %d (type = %d)",
546 if (!PQgetisnull(pg_info->
res,
549 atoi(PQgetvalue(pg_info->
res,
592 G_warning(
_(
"No geometry or topo geometry column defined"));
604 "Primary key not defined."));
608 #ifdef USE_CURSOR_RND
628 if (PQntuples(pg_info->
res) == CURSOR_PAGE &&
632 PQclear(pg_info->
res);
634 sprintf(stmt,
"FETCH %d in %s", CURSOR_PAGE, pg_info->
cursor_name);
636 pg_info->
res = PQexec(pg_info->
conn, stmt);
637 if (!pg_info->
res || PQresultStatus(pg_info->
res) != PGRES_TUPLES_OK) {
638 error_tuples(pg_info);
658 seq_type = atoi(PQgetvalue(pg_info->
res, pg_info->
next_line, 2));
669 strlen(PQgetvalue(pg_info->
res, pg_info->
next_line, 1)) !=
671 G_warning(
_(
"Inconsistency in topology: detected centroid "
672 "(should be point)"));
675 int left_face, right_face;
682 if (type ==
GV_LINE && (left_face != 0 || right_face != 0))
683 G_warning(
_(
"Inconsistency in topology: detected boundary "
684 "(should be line)"));
690 data = (
char *)PQgetvalue(pg_info->
res, pg_info->
next_line, 0);
703 if (!PQgetisnull(pg_info->
res, pg_info->
next_line, col_idx))
704 cat = atoi(PQgetvalue(pg_info->
res, pg_info->
next_line, col_idx));
733 unsigned char *hex_to_wkb(
const char *hex_data,
int *nbytes)
738 length = strlen(hex_data) / 2 + 1;
739 if (length > wkb_data_length) {
740 wkb_data_length = length;
741 wkb_data =
G_realloc(wkb_data, wkb_data_length);
744 *nbytes = length - 1;
745 for (i = 0; i < (*nbytes); i++) {
747 (
unsigned char)((hex_data[2 * i] >
'F' ? hex_data[2 * i] - 0x57
748 : hex_data[2 * i] >
'9' ? hex_data[2 * i] - 0x37
749 : hex_data[2 * i] - 0x30)
751 wkb_data[i] |= (
unsigned char)(hex_data[2 * i + 1] >
'F'
752 ? hex_data[2 * i + 1] - 0x57
753 : hex_data[2 * i + 1] >
'9'
754 ? hex_data[2 * i + 1] - 0x37
755 : hex_data[2 * i + 1] - 0x30);
758 wkb_data[(*nbytes)] = 0;
781 struct feat_parts *fparts)
783 int ret, byte_order, nbytes, is3D;
784 unsigned char *wkb_data;
785 unsigned int wkb_flags;
802 wkb_data = hex_to_wkb(data, &nbytes);
807 G_debug(3,
"Vect__cache_feature_pg(): invalid geometry");
808 G_warning(
_(
"Invalid WKB content: %d bytes"), nbytes);
812 G_debug(3,
"Vect__cache_feature_pg(): no geometry");
818 memcpy(&wkb_flags, wkb_data + 1, 4);
821 wkb_flags = SWAP32(wkb_flags);
823 if (wkb_flags & 0x40000000) {
824 G_warning(
_(
"Reading EWKB with 4-dimensional coordinates (XYZM) "
825 "is not supported"));
834 if (nbytes > 9 && ((byte_order ==
ENDIAN_BIG && (wkb_data[1] & 0x20)) ||
836 memmove(wkb_data + 5, wkb_data + 9, nbytes - 9);
839 wkb_data[1] &= (~0x20);
841 wkb_data[4] &= (~0x20);
844 if (nbytes < 9 && nbytes != -1) {
854 is3D = wkb_data[4] & 0x80 || wkb_data[2] & 0x80;
858 is3D = wkb_data[1] & 0x80 || wkb_data[3] & 0x80;
860 G_debug(3,
"Vect__cache_feature_pg(): sf_type = %d", ftype);
880 ret = point_from_wkb(wkb_data, nbytes, byte_order, is3D,
882 add_fpart(fparts, ftype, 0, 1);
887 ret = linestring_from_wkb(wkb_data, nbytes, byte_order, is3D,
889 add_fpart(fparts, ftype, 0, 1);
891 else if (ftype ==
SF_POLYGON && !skip_polygon) {
895 ret = polygon_from_wkb(wkb_data, nbytes, byte_order, is3D,
cache,
897 add_fpart(fparts, ftype, 0, nrings);
901 ret = geometry_collection_from_wkb(wkb_data, nbytes, byte_order, is3D,
905 G_warning(
_(
"Unsupported feature type %d"), ftype);
932 int point_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
937 if (nbytes < 21 && nbytes != -1)
941 memcpy(&
x, wkb_data + 5, 8);
942 memcpy(&y, wkb_data + 5 + 8, 8);
950 if (nbytes < 29 && nbytes != -1)
953 memcpy(&z, wkb_data + 5 + 16, 8);
967 return 5 + 8 * (with_z ==
WITH_Z ? 3 : 2);
984 int linestring_from_wkb(
const unsigned char *wkb_data,
int nbytes,
985 int byte_order,
int with_z,
struct line_pnts *line_p,
988 int npoints, point_size, buff_min_size,
offset;
997 if (is_ring && nbytes < 4 && nbytes != -1)
998 return error_corrupted_data(
NULL);
1001 memcpy(&npoints, wkb_data + (5 -
offset), 4);
1004 npoints = SWAP32(npoints);
1010 point_size = with_z ? 24 : 16;
1011 if (npoints < 0 || npoints > INT_MAX / point_size)
1012 return error_corrupted_data(
NULL);
1014 buff_min_size = point_size * npoints;
1016 if (nbytes != -1 && buff_min_size > nbytes - (9 -
offset))
1017 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1023 for (i = 0; i < npoints; i++) {
1024 memcpy(&
x, wkb_data + (9 -
offset) + i * point_size, 8);
1025 memcpy(&y, wkb_data + (9 -
offset) + 8 + i * point_size, 8);
1027 memcpy(&z, wkb_data + (9 -
offset) + 16 + i * point_size, 8);
1060 int polygon_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
1063 int data_offset, i, nsize, isize;
1067 if (nbytes < 9 && nbytes != -1)
1071 memcpy(nrings, wkb_data + 5, 4);
1073 *nrings = SWAP32(*nrings);
1078 num_of_rings = *nrings;
1085 if (nbytes != -1 && nbytes - 9 < num_of_rings * 4) {
1086 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1091 nbytes -= data_offset;
1095 for (i = 0; i < num_of_rings; i++) {
1102 linestring_from_wkb(wkb_data + data_offset, nbytes, byte_order, with_z,
1111 data_offset += isize;
1133 int geometry_collection_from_wkb(
const unsigned char *wkb_data,
int nbytes,
1134 int byte_order,
int with_z,
1136 struct feat_parts *fparts)
1138 int ipart, nparts, data_offset, nsize;
1139 unsigned char *wkb_subdata;
1142 if (nbytes < 9 && nbytes != -1)
1143 return error_corrupted_data(
NULL);
1146 memcpy(&nparts, wkb_data + 5, 4);
1148 nparts = SWAP32(nparts);
1150 if (nparts < 0 || nparts > INT_MAX / 9) {
1151 return error_corrupted_data(
NULL);
1153 G_debug(5,
"\t(geometry collections) parts: %d", nparts);
1156 if (nbytes != -1 && nbytes - 9 < nparts * 9) {
1157 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1162 nbytes -= data_offset;
1168 for (ipart = 0; ipart < nparts; ipart++) {
1169 wkb_subdata = (
unsigned char *)wkb_data + data_offset;
1170 if (nbytes < 9 && nbytes != -1)
1171 return error_corrupted_data(
NULL);
1182 nsize = point_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
1185 add_fpart(fparts, ftype, cache->
lines_next, 1);
1190 nsize = linestring_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
1193 add_fpart(fparts, ftype, cache->
lines_next, 1);
1200 nsize = polygon_from_wkb(wkb_subdata, nbytes, byte_order, with_z,
1202 add_fpart(fparts, ftype, idx, nrings);
1206 geometry_collection_from_wkb(wkb_subdata, nbytes, byte_order,
1207 with_z, cache, fparts);
1210 G_warning(
_(
"Unsupported feature type %d"), ftype);
1217 data_offset += nsize;
1230 int error_corrupted_data(
const char *msg)
1253 int fetch_all,
int built_level)
1267 if (pg_info->
where) {
1276 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1277 "\"%s\".\"%s\" WHERE \"%s\"=%s ORDER BY \"%s\"",
1286 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1287 "\"%s\".\"%s\" ORDER BY \"%s\"",
1298 "DECLARE %s CURSOR FOR "
1299 "SELECT geom,id,type,fid FROM ("
1300 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1301 "\"%s\".node AS tt "
1302 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 1 AND (%s).id = "
1304 "WHERE containing_face IS NULL AND node_id NOT IN "
1305 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1306 "GROUP BY start_node UNION ALL "
1307 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1309 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1310 "\"%s\".node AS tt "
1311 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 3 AND (%s).id = %s "
1312 "WHERE containing_face IS NOT NULL AND node_id NOT IN "
1313 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1314 "GROUP BY start_node UNION ALL "
1315 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1317 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1318 "\"%s\".edge AS tt "
1319 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1321 "WHERE left_face = 0 AND right_face = 0 UNION ALL "
1322 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1323 "\"%s\".edge AS tt "
1324 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1326 "WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY type,id",
1348 sprintf(stmt,
"FETCH ALL in %s", pg_info->
cursor_name);
1350 sprintf(stmt,
"FETCH %d in %s", CURSOR_PAGE, pg_info->
cursor_name);
1353 PQexec(pg_info->
conn, stmt);
1354 if (!pg_info->
res || PQresultStatus(pg_info->
res) != PGRES_TUPLES_OK) {
1355 error_tuples(pg_info);
1382 G_debug(3,
"Vect__open_cursor_line_pg(): fid range = %d-%d, type = %d", fid,
1383 fid + CURSOR_PAGE, type);
1395 "DECLARE %s CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
1396 "WHERE %s BETWEEN %d AND %d ORDER BY %s",
1399 fid, fid + CURSOR_PAGE, pg_info->
fid_column);
1404 G_warning(
_(
"Unsupported feature type %d"), type);
1412 "DECLARE %s CURSOR FOR SELECT geom,containing_face "
1413 " FROM \"%s\".node WHERE node_id BETWEEN %d AND %d ORDER "
1421 "DECLARE %s CURSOR FOR SELECT geom,left_face,right_face "
1422 " FROM \"%s\".edge WHERE edge_id BETWEEN %d AND %d ORDER "
1434 sprintf(stmt,
"FETCH ALL in %s", pg_info->
cursor_name);
1435 pg_info->
res = PQexec(pg_info->
conn, stmt);
1436 if (!pg_info->
res || PQresultStatus(pg_info->
res) != PGRES_TUPLES_OK) {
1437 error_tuples(pg_info);
1455 PQclear(pg_info->
res);
1491 sprintf(stmt,
"SELECT %s FROM \"%s\".\"%s\" WHERE %s = %d",
1498 G_warning(
_(
"Unsupported feature type %d"), type);
1512 nodeid =
"containing_face";
1516 "SELECT tt.geom,tt.containing_face,ft.%s FROM \"%s\".node "
1518 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = %d and "
1520 "WHERE node_id = %d",
1528 "SELECT tt.geom,tt.left_face,tt.right_face,ft.%s FROM "
1529 "\"%s\".edge AS tt "
1530 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 and "
1531 "(%s).id = edge_id "
1532 "WHERE edge_id = %d",
1542 pg_info->
res = PQexec(pg_info->
conn, stmt);
1543 if (!pg_info->
res || PQresultStatus(pg_info->
res) != PGRES_TUPLES_OK) {
1544 error_tuples(pg_info);
1568 G_debug(3,
"Vect__execute_pg(): %s", stmt);
1569 result = PQexec(conn, stmt);
1570 if (!result || PQresultStatus(result) != PGRES_COMMAND_OK) {
1575 stmt_len = strlen(stmt);
1576 strncpy(stmt_prt, stmt, stmt_len > 511 ? 511 : stmt_len);
1577 stmt_prt[stmt_len > 511 ? 511 : stmt_len] =
'\0';
1578 G_warning(
_(
"Execution failed: %s (...)\nReason: %s"), stmt_prt,
1579 PQerrorMessage(conn));
1603 G_debug(3,
"Vect__execute_get_value_pg(): %s", stmt);
1604 result = PQexec(conn, stmt);
1605 if (!result || PQresultStatus(result) != PGRES_TUPLES_OK ||
1606 PQntuples(result) != 1) {
1609 G_warning(
_(
"Execution failed: %s\nReason: %s"), stmt,
1610 PQerrorMessage(conn));
1614 ret = atoi(PQgetvalue(result, 0, 0));
1630 if (!incr && !cache->
lines) {
1646 for (i = cache->
lines_alloc - num; i < cache->lines_alloc; i++) {
1659 void add_fpart(
struct feat_parts *fparts,
SF_FeatureType ftype,
int idx,
1665 if (fparts->a_parts == 0 || fparts->n_parts >= fparts->a_parts) {
1666 if (fparts->a_parts == 0)
1667 fparts->a_parts = 1;
1669 fparts->a_parts += fparts->n_parts;
1674 (
int *)
G_realloc(fparts->nlines, fparts->a_parts *
sizeof(
int));
1676 (
int *)
G_realloc(fparts->idx, fparts->a_parts *
sizeof(
int));
1679 fparts->ftype[fparts->n_parts] = ftype;
1680 fparts->idx[fparts->n_parts] = idx;
1681 fparts->nlines[fparts->n_parts] = nlines;
1715 for (i = 0; i <
list.n_values; i++) {
1716 if (
list.id[i] == centroid) {
1739 G_warning(
_(
"Unable to read features. Reason:\n%s"),
1740 PQresultErrorMessage(pg_info->
res));
1743 PQclear(pg_info->
res);
void G_free(void *)
Free allocated memory.
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
void G_free_tokens(char **)
Free memory allocated to tokens.
int G_asprintf(char **, const char *,...) __attribute__((format(printf
int G_number_of_tokens(char **)
Return number of tokens.
int G_debug(int, const char *,...) __attribute__((format(printf
char ** G_tokenize(const char *, const char *)
Tokenize string.
int Vect_reset_cats(struct line_cats *)
Reset category structure to make sure cats structure is clean to be re-used.
void Vect_line_box(const struct line_pnts *, struct bound_box *)
Get bounding box of line.
int Vect_cat_set(struct line_cats *, int, int)
Add new field/cat to category structure if doesn't exist yet.
int Vect_get_constraint_box(struct Map_info *, struct bound_box *)
Get constraint box.
int Vect_box_overlap(const struct bound_box *, const struct bound_box *)
Tests for overlap of two boxes.
int Vect_get_area_box(struct Map_info *, int, struct bound_box *)
Get bounding box of area.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
int Vect_select_lines_by_box(struct Map_info *, const struct bound_box *, int, struct boxlist *)
Select lines with bounding boxes by box.
void Vect_reset_line(struct line_pnts *)
Reset line.
int Vect_append_point(struct line_pnts *, double, double, double)
Appends one point to the end of a line.
int Vect_append_points(struct line_pnts *, const struct line_pnts *, int)
Appends points to the end of a line.
SF_FeatureType
Simple feature types.
#define GV_POINT
Feature types used in memory on run time (may change)
#define GV_BUILD_CENTROIDS
Topology levels - assign centroids to areas.
#define GV_FORWARD
Line direction indicator forward/backward.
int dig_init_boxlist(struct boxlist *, int)
#define ENDIAN_LITTLE
Endian check.
int V2_read_line_pg(struct Map_info *Map NOPG_UNUSED, struct line_pnts *line_p NOPG_UNUSED, struct line_cats *line_c NOPG_UNUSED, int line NOPG_UNUSED)
Read feature from PostGIS layer on topological level.
int Vect__close_cursor_pg(struct Format_info_pg *pg_info)
Close select cursor.
int Vect__execute_get_value_pg(PGconn *conn, const char *stmt)
Execute SQL statement and get value.
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
SF_FeatureType Vect__cache_feature_pg(const char *data, int skip_polygon, int force_type, struct Format_info_cache *cache, struct feat_parts *fparts)
Read geometry from HEX data.
SF_FeatureType get_feature(struct Map_info *, int, int)
Read feature geometry.
int V1_read_line_pg(struct Map_info *Map NOPG_UNUSED, struct line_pnts *line_p NOPG_UNUSED, struct line_cats *line_c NOPG_UNUSED, off_t offset NOPG_UNUSED)
Read feature from PostGIS layer at given offset (level 1 without topology)
int Vect__open_cursor_line_pg(struct Format_info_pg *pg_info, int fid, int type)
Open select cursor for random access (internal use only)
int V1_read_next_line_pg(struct Map_info *Map NOPG_UNUSED, struct line_pnts *line_p NOPG_UNUSED, struct line_cats *line_c NOPG_UNUSED)
Read next feature from PostGIS layer. Skip empty features (level 1 without topology)....
int Vect__select_line_pg(struct Format_info_pg *pg_info, int fid, int type)
Select feature (internal use only)
void Vect__reallocate_cache(struct Format_info_cache *cache, int num, int incr)
Reallocate lines cache.
int V2_read_next_line_pg(struct Map_info *Map NOPG_UNUSED, struct line_pnts *line_p NOPG_UNUSED, struct line_cats *line_c NOPG_UNUSED)
Read next feature from PostGIS layer on topological level (simple feature access).
int Vect__open_cursor_next_line_pg(struct Format_info_pg *pg_info, int fetch_all, int built_level)
Create select cursor for sequential access (internal use only)
struct dig_head head
Header info.
plus_t next_line
Feature id for sequential access.
int type
Feature type constraint.
int type_flag
Non-zero value to enable feature type constraint.
struct Map_info::@11 constraint
Constraints for sequential feature access.
int region_flag
Non-zero value to enable region constraint.
struct Format_info fInfo
Format info for non-native formats.
struct Plus_head plus
Plus info (topology, version, ...)
off_t offset
Offset in coor file for line.
void * topo
Topology info.
plus_t area
Area number, negative for duplicate centroid.
struct P_line ** Line
Array of vector geometries.
int built
Highest level of topology currently available.
List of bounding boxes with id.
off_t last_offset
Offset of last read line.
Feature geometry info - coordinates.
int n_points
Number of points.