31#include "local_proto.h"
34#include "pg_local_proto.h"
38static unsigned char *wkb_data;
39static unsigned int wkb_data_length;
44static unsigned char *hex_to_wkb(
const char *,
int *);
45static int point_from_wkb(
const unsigned char *,
int,
int,
int,
47static int linestring_from_wkb(
const unsigned char *,
int,
int,
int,
49static int polygon_from_wkb(
const unsigned char *,
int,
int,
int,
51static int geometry_collection_from_wkb(
const unsigned char *,
int,
int,
int,
54static int error_corrupted_data(
const char *);
62#define NOPG_UNUSED G_UNUSED
91 G_debug(3,
"V1_read_next_line_pg()");
128 G_debug(3,
"V2_read_next_line_pg()");
132 if (
Map->constraint.region_flag)
137 line =
Map->next_line;
139 if (
Map->next_line >
Map->plus.n_lines)
142 Line =
Map->plus.Line[line];
148 if (
Map->constraint.type_flag) {
150 if (!(Line->
type &
Map->constraint.type)) {
157 G_debug(4,
"Determine centroid for simple features");
172 for (i = 0; i <
list.n_values; i++) {
173 if (
list.id[i] == line) {
197 G_warning(
_(
"Unexpected feature type (%d) - should be (%d)"),
203 if (
Map->constraint.region_flag) {
219 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
256 G_debug(3,
"V1_read_line_pg(): offset = %lu offset_num = %lu", (
long)
offset,
257 (
long)
pg_info->offset.array_num);
271 if (
pg_info->cache.fid != fid) {
274 G_debug(3,
"read (%s) feature (fid = %ld) to cache",
279 G_warning(
_(
"Feature %ld without geometry skipped"), fid);
295 G_debug(3,
"read feature part: %d -> type = %d",
ipart, type);
305 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
339 G_warning(
_(
"Attempt to access feature with invalid id (%d)"), line);
343 Line =
Map->plus.Line[line];
345 G_warning(
_(
"Attempt to access dead feature %d"), line);
349 G_debug(4,
"V2_read_line_pg() line = %d type = %d offset = %" PRId64, line,
374 "Number of features in cache: %d"),
377 G_warning(
_(
"Feature %d: unexpected type (%d) - should be %d"),
387 G_warning(
_(
"Feature %d without geometry skipped"), line);
390 if (0 > (
int)
pg_info->cache.sf_type)
397 if (!
pg_info->toposchema_name) {
425 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
478 G_warning(
_(
"Feature %ld without geometry skipped"),
483 if ((
int)sf_type < 0) {
490 G_warning(
_(
"Feature without geometry. Skipped."));
508 G_debug(4,
"read next cached line %d (type = %d)",
514 if (!(
itype &
Map->constraint.type))
534 if (!
pg_info->toposchema_name) {
546 cat =
pg_info->cache.lines_cats[
Map->next_line - 1] =
551 pg_info->cache.lines_cats[
Map->next_line - 1] =
590 G_warning(
_(
"No geometry or topo geometry column defined"));
602 "Primary key not defined."));
654 if (
pg_info->toposchema_name) {
670 G_warning(
_(
"Inconsistency in topology: detected centroid "
671 "(should be point)"));
674 int left_face, right_face;
681 if (type ==
GV_LINE && (left_face != 0 || right_face != 0))
682 G_warning(
_(
"Inconsistency in topology: detected boundary "
683 "(should be line)"));
696 if (
pg_info->toposchema_name) {
707 G_debug(3,
"line=%d, type=%d -> cat=%d",
pg_info->cache.lines_next + 1,
732unsigned char *hex_to_wkb(
const char *
hex_data,
int *nbytes)
738 if (length > wkb_data_length) {
739 wkb_data_length = length;
740 wkb_data =
G_realloc(wkb_data, wkb_data_length);
743 *nbytes = length - 1;
744 for (i = 0; i < (*nbytes); i++) {
750 wkb_data[i] |= (
unsigned char)(
hex_data[2 * i + 1] >
'F'
757 wkb_data[(*nbytes)] = 0;
782 int ret, byte_order, nbytes,
is3D;
783 unsigned char *wkb_data;
792 cache->lines_next = 0;
793 cache->lines_num = 1;
801 wkb_data = hex_to_wkb(data, &nbytes);
806 G_debug(3,
"Vect__cache_feature_pg(): invalid geometry");
807 G_warning(
_(
"Invalid WKB content: %d bytes"), nbytes);
811 G_debug(3,
"Vect__cache_feature_pg(): no geometry");
823 G_warning(
_(
"Reading EWKB with 4-dimensional coordinates (XYZM) "
824 "is not supported"));
833 if (nbytes > 9 && ((byte_order ==
ENDIAN_BIG && (wkb_data[1] & 0x20)) ||
835 memmove(wkb_data + 5, wkb_data + 9, nbytes - 9);
838 wkb_data[1] &= (~0x20);
840 wkb_data[4] &= (~0x20);
843 if (nbytes < 9 && nbytes != -1) {
853 is3D = wkb_data[4] & 0x80 || wkb_data[2] & 0x80;
857 is3D = wkb_data[1] & 0x80 || wkb_data[3] & 0x80;
859 G_debug(3,
"Vect__cache_feature_pg(): sf_type = %d",
ftype);
879 ret = point_from_wkb(wkb_data, nbytes, byte_order,
is3D,
886 ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
is3D,
893 cache->lines_num = 0;
894 ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
is3D,
cache,
900 ret = geometry_collection_from_wkb(wkb_data, nbytes, byte_order,
is3D,
909 cache->lines_next = 0;
931int point_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
936 if (nbytes < 21 && nbytes != -1)
940 memcpy(&x, wkb_data + 5, 8);
941 memcpy(&y, wkb_data + 5 + 8, 8);
949 if (nbytes < 29 && nbytes != -1)
952 memcpy(&z, wkb_data + 5 + 16, 8);
966 return 5 + 8 * (with_z ==
WITH_Z ? 3 : 2);
983int linestring_from_wkb(
const unsigned char *wkb_data,
int nbytes,
996 if (
is_ring && nbytes < 4 && nbytes != -1)
997 return error_corrupted_data(
NULL);
1003 npoints =
SWAP32(npoints);
1011 return error_corrupted_data(
NULL);
1016 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1022 for (i = 0; i < npoints; i++) {
1059int polygon_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
1066 if (nbytes < 9 && nbytes != -1)
1085 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1101 linestring_from_wkb(wkb_data +
data_offset, nbytes, byte_order, with_z,
1132int geometry_collection_from_wkb(
const unsigned char *wkb_data,
int nbytes,
1133 int byte_order,
int with_z,
1141 if (nbytes < 9 && nbytes != -1)
1142 return error_corrupted_data(
NULL);
1150 return error_corrupted_data(
NULL);
1155 if (nbytes != -1 && nbytes - 9 <
nparts * 9) {
1156 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1169 if (nbytes < 9 && nbytes != -1)
1170 return error_corrupted_data(
NULL);
1205 geometry_collection_from_wkb(
wkb_subdata, nbytes, byte_order,
1229int error_corrupted_data(
const char *
msg)
1263 if (!
pg_info->toposchema_name) {
1275 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1276 "\"%s\".\"%s\" WHERE \"%s\"=%s ORDER BY \"%s\"",
1285 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1286 "\"%s\".\"%s\" ORDER BY \"%s\"",
1297 "DECLARE %s CURSOR FOR "
1298 "SELECT geom,id,type,fid FROM ("
1299 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1300 "\"%s\".node AS tt "
1301 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 1 AND (%s).id = "
1303 "WHERE containing_face IS NULL AND node_id NOT IN "
1304 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1305 "GROUP BY start_node UNION ALL "
1306 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1308 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1309 "\"%s\".node AS tt "
1310 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 3 AND (%s).id = %s "
1311 "WHERE containing_face IS NOT NULL AND node_id NOT IN "
1312 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1313 "GROUP BY start_node UNION ALL "
1314 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1316 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1317 "\"%s\".edge AS tt "
1318 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1320 "WHERE left_face = 0 AND right_face = 0 UNION ALL "
1321 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1322 "\"%s\".edge AS tt "
1323 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1325 "WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY type,id",
1347 snprintf(stmt,
sizeof(stmt),
"FETCH ALL in %s",
pg_info->cursor_name);
1382 G_debug(3,
"Vect__open_cursor_line_pg(): fid range = %d-%d, type = %d", fid,
1392 if (!
pg_info->toposchema_name) {
1395 "DECLARE %s CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
1396 "WHERE %s BETWEEN %d AND %d ORDER BY %s",
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 snprintf(stmt,
sizeof(stmt),
"FETCH ALL in %s",
pg_info->cursor_name);
1489 if (!
pg_info->toposchema_name) {
1492 "SELECT %s FROM \"%s\".\"%s\" WHERE %s = %d",
1499 G_warning(
_(
"Unsupported feature type %d"), type);
1513 nodeid =
"containing_face";
1517 "SELECT tt.geom,tt.containing_face,ft.%s FROM \"%s\".node "
1519 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = %d and "
1521 "WHERE node_id = %d",
1529 "SELECT tt.geom,tt.left_face,tt.right_face,ft.%s FROM "
1530 "\"%s\".edge AS tt "
1531 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 and "
1532 "(%s).id = edge_id "
1533 "WHERE edge_id = %d",
1569 G_debug(3,
"Vect__execute_pg(): %s", stmt);
1570 result =
PQexec(conn, stmt);
1604 G_debug(3,
"Vect__execute_get_value_pg(): %s", stmt);
1605 result =
PQexec(conn, stmt);
1610 G_warning(
_(
"Execution failed: %s\nReason: %s"), stmt,
1631 if (!incr && !cache->
lines) {
1667 if (
fparts->a_parts == 0)
1706 Line =
Map->plus.Line[centroid];
1716 for (i = 0; i <
list.n_values; i++) {
1717 if (
list.id[i] == centroid) {
1740 G_warning(
_(
"Unable to read features. Reason:\n%s"),
Main header of GRASS DataBase Management Interface.
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
char ** G_tokenize(const char *, const char *)
Tokenize string.
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
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.
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.
struct line_pnts * Vect_new_line_struct(void)
Creates and initializes a line_pnts structure.
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 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 V2_read_next_line_pg(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c)
Read next feature from PostGIS layer on topological level (simple feature access).
int Vect__execute_pg(PGconn *conn, const char *stmt)
Execute SQL statement.
int V2_read_line_pg(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, int line)
Read feature from PostGIS layer on topological level.
int V1_read_next_line_pg(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c)
Read next feature from PostGIS layer. Skip empty features (level 1 without topology)....
int V1_read_line_pg(struct Map_info *Map, struct line_pnts *line_p, struct line_cats *line_c, off_t offset)
Read feature from PostGIS layer at given offset (level 1 without topology)
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 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 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 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)
off_t offset
Offset in coor file for line.
void * topo
Topology info.
plus_t area
Area number, negative for duplicate centroid.
List of bounding boxes with id.
Feature geometry info - coordinates.