33#include "local_proto.h"
36#include "pg_local_proto.h"
40static unsigned char *wkb_data;
41static unsigned int wkb_data_length;
46static unsigned char *hex_to_wkb(
const char *,
int *);
47static int point_from_wkb(
const unsigned char *,
int,
int,
int,
49static int linestring_from_wkb(
const unsigned char *,
int,
int,
int,
51static int polygon_from_wkb(
const unsigned char *,
int,
int,
int,
53static int geometry_collection_from_wkb(
const unsigned char *,
int,
int,
int,
56static int error_corrupted_data(
const char *);
64#define NOPG_UNUSED UNUSED
93 G_debug(3,
"V1_read_next_line_pg()");
130 G_debug(3,
"V2_read_next_line_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");
174 for (i = 0; i <
list.n_values; i++) {
175 if (
list.id[i] == line) {
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"));
258 G_debug(3,
"V1_read_line_pg(): offset = %lu offset_num = %lu", (
long)
offset,
259 (
long)
pg_info->offset.array_num);
273 if (
pg_info->cache.fid != fid) {
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"));
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,
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);
392 if (0 > (
int)
pg_info->cache.sf_type)
399 if (!
pg_info->toposchema_name) {
427 G_fatal_error(
_(
"GRASS is not compiled with PostgreSQL support"));
480 G_warning(
_(
"Feature %ld without geometry skipped"),
485 if ((
int)sf_type < 0) {
492 G_warning(
_(
"Feature without geometry. Skipped."));
510 G_debug(4,
"read next cached line %d (type = %d)",
516 if (!(
itype &
Map->constraint.type))
536 if (!
pg_info->toposchema_name) {
548 cat =
pg_info->cache.lines_cats[
Map->next_line - 1] =
553 pg_info->cache.lines_cats[
Map->next_line - 1] =
592 G_warning(
_(
"No geometry or topo geometry column defined"));
604 "Primary key not defined."));
656 if (
pg_info->toposchema_name) {
672 G_warning(
_(
"Inconsistency in topology: detected centroid "
673 "(should be point)"));
676 int left_face, right_face;
683 if (type ==
GV_LINE && (left_face != 0 || right_face != 0))
684 G_warning(
_(
"Inconsistency in topology: detected boundary "
685 "(should be line)"));
698 if (
pg_info->toposchema_name) {
709 G_debug(3,
"line=%d, type=%d -> cat=%d",
pg_info->cache.lines_next + 1,
734unsigned char *hex_to_wkb(
const char *
hex_data,
int *nbytes)
740 if (length > wkb_data_length) {
741 wkb_data_length = length;
742 wkb_data =
G_realloc(wkb_data, wkb_data_length);
745 *nbytes = length - 1;
746 for (i = 0; i < (*nbytes); i++) {
752 wkb_data[i] |= (
unsigned char)(
hex_data[2 * i + 1] >
'F'
759 wkb_data[(*nbytes)] = 0;
784 int ret, byte_order, nbytes,
is3D;
785 unsigned char *wkb_data;
794 cache->lines_next = 0;
795 cache->lines_num = 1;
803 wkb_data = hex_to_wkb(data, &nbytes);
808 G_debug(3,
"Vect__cache_feature_pg(): invalid geometry");
809 G_warning(
_(
"Invalid WKB content: %d bytes"), nbytes);
813 G_debug(3,
"Vect__cache_feature_pg(): no geometry");
825 G_warning(
_(
"Reading EWKB with 4-dimensional coordinates (XYZM) "
826 "is not supported"));
835 if (nbytes > 9 && ((byte_order ==
ENDIAN_BIG && (wkb_data[1] & 0x20)) ||
837 memmove(wkb_data + 5, wkb_data + 9, nbytes - 9);
840 wkb_data[1] &= (~0x20);
842 wkb_data[4] &= (~0x20);
845 if (nbytes < 9 && nbytes != -1) {
855 is3D = wkb_data[4] & 0x80 || wkb_data[2] & 0x80;
859 is3D = wkb_data[1] & 0x80 || wkb_data[3] & 0x80;
861 G_debug(3,
"Vect__cache_feature_pg(): sf_type = %d",
ftype);
881 ret = point_from_wkb(wkb_data, nbytes, byte_order,
is3D,
888 ret = linestring_from_wkb(wkb_data, nbytes, byte_order,
is3D,
895 cache->lines_num = 0;
896 ret = polygon_from_wkb(wkb_data, nbytes, byte_order,
is3D,
cache,
902 ret = geometry_collection_from_wkb(wkb_data, nbytes, byte_order,
is3D,
911 cache->lines_next = 0;
933int point_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
938 if (nbytes < 21 && nbytes != -1)
942 memcpy(&x, wkb_data + 5, 8);
943 memcpy(&y, wkb_data + 5 + 8, 8);
951 if (nbytes < 29 && nbytes != -1)
954 memcpy(&z, wkb_data + 5 + 16, 8);
968 return 5 + 8 * (with_z ==
WITH_Z ? 3 : 2);
985int linestring_from_wkb(
const unsigned char *wkb_data,
int nbytes,
998 if (
is_ring && nbytes < 4 && nbytes != -1)
999 return error_corrupted_data(
NULL);
1005 npoints =
SWAP32(npoints);
1013 return error_corrupted_data(
NULL);
1018 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1024 for (i = 0; i < npoints; i++) {
1061int polygon_from_wkb(
const unsigned char *wkb_data,
int nbytes,
int byte_order,
1068 if (nbytes < 9 && nbytes != -1)
1087 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1103 linestring_from_wkb(wkb_data +
data_offset, nbytes, byte_order, with_z,
1134int geometry_collection_from_wkb(
const unsigned char *wkb_data,
int nbytes,
1135 int byte_order,
int with_z,
1143 if (nbytes < 9 && nbytes != -1)
1144 return error_corrupted_data(
NULL);
1152 return error_corrupted_data(
NULL);
1157 if (nbytes != -1 && nbytes - 9 <
nparts * 9) {
1158 return error_corrupted_data(
_(
"Length of input WKB is too small"));
1171 if (nbytes < 9 && nbytes != -1)
1172 return error_corrupted_data(
NULL);
1207 geometry_collection_from_wkb(
wkb_subdata, nbytes, byte_order,
1231int error_corrupted_data(
const char *
msg)
1265 if (!
pg_info->toposchema_name) {
1277 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1278 "\"%s\".\"%s\" WHERE \"%s\"=%s ORDER BY \"%s\"",
1287 "DECLARE %s CURSOR FOR SELECT \"%s\",\"%s\" FROM "
1288 "\"%s\".\"%s\" ORDER BY \"%s\"",
1299 "DECLARE %s CURSOR FOR "
1300 "SELECT geom,id,type,fid FROM ("
1301 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1302 "\"%s\".node AS tt "
1303 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 1 AND (%s).id = "
1305 "WHERE containing_face IS NULL AND node_id NOT IN "
1306 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1307 "GROUP BY start_node UNION ALL "
1308 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1310 "SELECT tt.node_id AS id,tt.geom, %d AS type, ft.%s AS fid FROM "
1311 "\"%s\".node AS tt "
1312 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 3 AND (%s).id = %s "
1313 "WHERE containing_face IS NOT NULL AND node_id NOT IN "
1314 "(SELECT node FROM (SELECT start_node AS node FROM \"%s\".edge "
1315 "GROUP BY start_node UNION ALL "
1316 "SELECT end_node AS node FROM \"%s\".edge GROUP BY end_node) AS "
1318 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1319 "\"%s\".edge AS tt "
1320 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1322 "WHERE left_face = 0 AND right_face = 0 UNION ALL "
1323 "SELECT tt.edge_id AS id, tt.geom, %d AS type, ft.%s AS fid FROM "
1324 "\"%s\".edge AS tt "
1325 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 AND (%s).id = "
1327 "WHERE left_face != 0 OR right_face != 0 ) AS foo ORDER BY type,id",
1349 snprintf(stmt,
sizeof(stmt),
"FETCH ALL in %s",
pg_info->cursor_name);
1384 G_debug(3,
"Vect__open_cursor_line_pg(): fid range = %d-%d, type = %d", fid,
1394 if (!
pg_info->toposchema_name) {
1397 "DECLARE %s CURSOR FOR SELECT %s FROM \"%s\".\"%s\" "
1398 "WHERE %s BETWEEN %d AND %d ORDER BY %s",
1406 G_warning(
_(
"Unsupported feature type %d"), type);
1414 "DECLARE %s CURSOR FOR SELECT geom,containing_face "
1415 " FROM \"%s\".node WHERE node_id BETWEEN %d AND %d ORDER "
1423 "DECLARE %s CURSOR FOR SELECT geom,left_face,right_face "
1424 " FROM \"%s\".edge WHERE edge_id BETWEEN %d AND %d ORDER "
1436 snprintf(stmt,
sizeof(stmt),
"FETCH ALL in %s",
pg_info->cursor_name);
1491 if (!
pg_info->toposchema_name) {
1494 "SELECT %s FROM \"%s\".\"%s\" WHERE %s = %d",
1501 G_warning(
_(
"Unsupported feature type %d"), type);
1515 nodeid =
"containing_face";
1519 "SELECT tt.geom,tt.containing_face,ft.%s FROM \"%s\".node "
1521 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = %d and "
1523 "WHERE node_id = %d",
1531 "SELECT tt.geom,tt.left_face,tt.right_face,ft.%s FROM "
1532 "\"%s\".edge AS tt "
1533 "LEFT JOIN \"%s\".\"%s\" AS ft ON (%s).type = 2 and "
1534 "(%s).id = edge_id "
1535 "WHERE edge_id = %d",
1571 G_debug(3,
"Vect__execute_pg(): %s", stmt);
1572 result =
PQexec(conn, stmt);
1606 G_debug(3,
"Vect__execute_get_value_pg(): %s", stmt);
1607 result =
PQexec(conn, stmt);
1612 G_warning(
_(
"Execution failed: %s\nReason: %s"), stmt,
1633 if (!incr && !cache->
lines) {
1669 if (
fparts->a_parts == 0)
1708 Line =
Map->plus.Line[centroid];
1718 for (i = 0; i <
list.n_values; i++) {
1719 if (
list.id[i] == centroid) {
1742 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.